blob: 0c8bcb94934e02f1334b2285e1dd7050ca9f04db [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030037
38#include <libaudit.h>
39#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030040#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030041#include <linux/futex.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020042#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030043#include <linux/seccomp.h>
44#include <linux/filter.h>
45#include <linux/audit.h>
46#include <sys/ptrace.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030047
Ingo Molnar456857b2013-09-12 15:29:00 +020048/* For older distros: */
49#ifndef MAP_STACK
50# define MAP_STACK 0x20000
51#endif
52
53#ifndef MADV_HWPOISON
54# define MADV_HWPOISON 100
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -030055
Ingo Molnar456857b2013-09-12 15:29:00 +020056#endif
57
58#ifndef MADV_MERGEABLE
59# define MADV_MERGEABLE 12
60#endif
61
62#ifndef MADV_UNMERGEABLE
63# define MADV_UNMERGEABLE 13
64#endif
65
Ben Hutchings79d26a62014-02-06 01:00:35 +000066#ifndef EFD_SEMAPHORE
67# define EFD_SEMAPHORE 1
68#endif
69
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030070#ifndef EFD_NONBLOCK
71# define EFD_NONBLOCK 00004000
72#endif
73
74#ifndef EFD_CLOEXEC
75# define EFD_CLOEXEC 02000000
76#endif
77
78#ifndef O_CLOEXEC
79# define O_CLOEXEC 02000000
80#endif
81
82#ifndef SOCK_DCCP
83# define SOCK_DCCP 6
84#endif
85
86#ifndef SOCK_CLOEXEC
87# define SOCK_CLOEXEC 02000000
88#endif
89
90#ifndef SOCK_NONBLOCK
91# define SOCK_NONBLOCK 00004000
92#endif
93
94#ifndef MSG_CMSG_CLOEXEC
95# define MSG_CMSG_CLOEXEC 0x40000000
96#endif
97
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -030098#ifndef PERF_FLAG_FD_NO_GROUP
99# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
100#endif
101
102#ifndef PERF_FLAG_FD_OUTPUT
103# define PERF_FLAG_FD_OUTPUT (1UL << 1)
104#endif
105
106#ifndef PERF_FLAG_PID_CGROUP
107# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
108#endif
109
110#ifndef PERF_FLAG_FD_CLOEXEC
111# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
112#endif
113
114
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300115struct tp_field {
116 int offset;
117 union {
118 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
119 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
120 };
121};
122
123#define TP_UINT_FIELD(bits) \
124static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
125{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500126 u##bits value; \
127 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
128 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300129}
130
131TP_UINT_FIELD(8);
132TP_UINT_FIELD(16);
133TP_UINT_FIELD(32);
134TP_UINT_FIELD(64);
135
136#define TP_UINT_FIELD__SWAPPED(bits) \
137static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
138{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500139 u##bits value; \
140 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300141 return bswap_##bits(value);\
142}
143
144TP_UINT_FIELD__SWAPPED(16);
145TP_UINT_FIELD__SWAPPED(32);
146TP_UINT_FIELD__SWAPPED(64);
147
148static int tp_field__init_uint(struct tp_field *field,
149 struct format_field *format_field,
150 bool needs_swap)
151{
152 field->offset = format_field->offset;
153
154 switch (format_field->size) {
155 case 1:
156 field->integer = tp_field__u8;
157 break;
158 case 2:
159 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
160 break;
161 case 4:
162 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
163 break;
164 case 8:
165 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
166 break;
167 default:
168 return -1;
169 }
170
171 return 0;
172}
173
174static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
175{
176 return sample->raw_data + field->offset;
177}
178
179static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
180{
181 field->offset = format_field->offset;
182 field->pointer = tp_field__ptr;
183 return 0;
184}
185
186struct syscall_tp {
187 struct tp_field id;
188 union {
189 struct tp_field args, ret;
190 };
191};
192
193static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
194 struct tp_field *field,
195 const char *name)
196{
197 struct format_field *format_field = perf_evsel__field(evsel, name);
198
199 if (format_field == NULL)
200 return -1;
201
202 return tp_field__init_uint(field, format_field, evsel->needs_swap);
203}
204
205#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
206 ({ struct syscall_tp *sc = evsel->priv;\
207 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
208
209static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
210 struct tp_field *field,
211 const char *name)
212{
213 struct format_field *format_field = perf_evsel__field(evsel, name);
214
215 if (format_field == NULL)
216 return -1;
217
218 return tp_field__init_ptr(field, format_field);
219}
220
221#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
222 ({ struct syscall_tp *sc = evsel->priv;\
223 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
224
225static void perf_evsel__delete_priv(struct perf_evsel *evsel)
226{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300227 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300228 perf_evsel__delete(evsel);
229}
230
Namhyung Kim96695d42013-11-12 08:51:45 -0300231static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
232{
233 evsel->priv = malloc(sizeof(struct syscall_tp));
234 if (evsel->priv != NULL) {
235 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
236 goto out_delete;
237
238 evsel->handler = handler;
239 return 0;
240 }
241
242 return -ENOMEM;
243
244out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300245 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300246 return -ENOENT;
247}
248
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300249static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300250{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300251 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300252
David Ahern9aca7f12013-12-04 19:41:39 -0700253 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200254 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700255 evsel = perf_evsel__newtp("syscalls", direction);
256
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200257 if (IS_ERR(evsel))
258 return NULL;
259
260 if (perf_evsel__init_syscall_tp(evsel, handler))
261 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300262
263 return evsel;
264
265out_delete:
266 perf_evsel__delete_priv(evsel);
267 return NULL;
268}
269
270#define perf_evsel__sc_tp_uint(evsel, name, sample) \
271 ({ struct syscall_tp *fields = evsel->priv; \
272 fields->name.integer(&fields->name, sample); })
273
274#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
275 ({ struct syscall_tp *fields = evsel->priv; \
276 fields->name.pointer(&fields->name, sample); })
277
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300278struct syscall_arg {
279 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300280 struct thread *thread;
281 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300283 u8 idx;
284 u8 mask;
285};
286
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300287struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300288 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300289 int nr_entries;
290 const char **entries;
291};
292
293#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
294 .nr_entries = ARRAY_SIZE(array), \
295 .entries = array, \
296}
297
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300298#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
299 .offset = off, \
300 .nr_entries = ARRAY_SIZE(array), \
301 .entries = array, \
302}
303
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300304static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
305 const char *intfmt,
306 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300307{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300308 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300309 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300310
311 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300312 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300313
314 return scnprintf(bf, size, "%s", sa->entries[idx]);
315}
316
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300317static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
318 struct syscall_arg *arg)
319{
320 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
321}
322
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300323#define SCA_STRARRAY syscall_arg__scnprintf_strarray
324
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300325#if defined(__i386__) || defined(__x86_64__)
326/*
327 * FIXME: Make this available to all arches as soon as the ioctl beautifier
328 * gets rewritten to support all arches.
329 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300330static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
331 struct syscall_arg *arg)
332{
333 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
334}
335
336#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300337#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300338
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300339static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
340 struct syscall_arg *arg);
341
342#define SCA_FD syscall_arg__scnprintf_fd
343
344static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
345 struct syscall_arg *arg)
346{
347 int fd = arg->val;
348
349 if (fd == AT_FDCWD)
350 return scnprintf(bf, size, "CWD");
351
352 return syscall_arg__scnprintf_fd(bf, size, arg);
353}
354
355#define SCA_FDAT syscall_arg__scnprintf_fd_at
356
357static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
358 struct syscall_arg *arg);
359
360#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
361
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300362static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300363 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300364{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300365 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300366}
367
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300368#define SCA_HEX syscall_arg__scnprintf_hex
369
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300370static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
371 struct syscall_arg *arg)
372{
373 return scnprintf(bf, size, "%d", arg->val);
374}
375
376#define SCA_INT syscall_arg__scnprintf_int
377
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300378static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300379 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300380{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300381 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300382
383 if (prot == PROT_NONE)
384 return scnprintf(bf, size, "NONE");
385#define P_MMAP_PROT(n) \
386 if (prot & PROT_##n) { \
387 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
388 prot &= ~PROT_##n; \
389 }
390
391 P_MMAP_PROT(EXEC);
392 P_MMAP_PROT(READ);
393 P_MMAP_PROT(WRITE);
394#ifdef PROT_SEM
395 P_MMAP_PROT(SEM);
396#endif
397 P_MMAP_PROT(GROWSDOWN);
398 P_MMAP_PROT(GROWSUP);
399#undef P_MMAP_PROT
400
401 if (prot)
402 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
403
404 return printed;
405}
406
407#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
408
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300409static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300410 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300411{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300412 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300413
414#define P_MMAP_FLAG(n) \
415 if (flags & MAP_##n) { \
416 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
417 flags &= ~MAP_##n; \
418 }
419
420 P_MMAP_FLAG(SHARED);
421 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400422#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300423 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400424#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300425 P_MMAP_FLAG(ANONYMOUS);
426 P_MMAP_FLAG(DENYWRITE);
427 P_MMAP_FLAG(EXECUTABLE);
428 P_MMAP_FLAG(FILE);
429 P_MMAP_FLAG(FIXED);
430 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600431#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300432 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600433#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300434 P_MMAP_FLAG(LOCKED);
435 P_MMAP_FLAG(NONBLOCK);
436 P_MMAP_FLAG(NORESERVE);
437 P_MMAP_FLAG(POPULATE);
438 P_MMAP_FLAG(STACK);
439#ifdef MAP_UNINITIALIZED
440 P_MMAP_FLAG(UNINITIALIZED);
441#endif
442#undef P_MMAP_FLAG
443
444 if (flags)
445 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
446
447 return printed;
448}
449
450#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
451
Alex Snast86998dd2014-08-13 18:42:40 +0300452static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
453 struct syscall_arg *arg)
454{
455 int printed = 0, flags = arg->val;
456
457#define P_MREMAP_FLAG(n) \
458 if (flags & MREMAP_##n) { \
459 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
460 flags &= ~MREMAP_##n; \
461 }
462
463 P_MREMAP_FLAG(MAYMOVE);
464#ifdef MREMAP_FIXED
465 P_MREMAP_FLAG(FIXED);
466#endif
467#undef P_MREMAP_FLAG
468
469 if (flags)
470 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
471
472 return printed;
473}
474
475#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
476
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300477static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300478 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300479{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300480 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300481
482 switch (behavior) {
483#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
484 P_MADV_BHV(NORMAL);
485 P_MADV_BHV(RANDOM);
486 P_MADV_BHV(SEQUENTIAL);
487 P_MADV_BHV(WILLNEED);
488 P_MADV_BHV(DONTNEED);
489 P_MADV_BHV(REMOVE);
490 P_MADV_BHV(DONTFORK);
491 P_MADV_BHV(DOFORK);
492 P_MADV_BHV(HWPOISON);
493#ifdef MADV_SOFT_OFFLINE
494 P_MADV_BHV(SOFT_OFFLINE);
495#endif
496 P_MADV_BHV(MERGEABLE);
497 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600498#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300499 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600500#endif
501#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300502 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600503#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300504#ifdef MADV_DONTDUMP
505 P_MADV_BHV(DONTDUMP);
506#endif
507#ifdef MADV_DODUMP
508 P_MADV_BHV(DODUMP);
509#endif
510#undef P_MADV_PHV
511 default: break;
512 }
513
514 return scnprintf(bf, size, "%#x", behavior);
515}
516
517#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
518
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300519static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
520 struct syscall_arg *arg)
521{
522 int printed = 0, op = arg->val;
523
524 if (op == 0)
525 return scnprintf(bf, size, "NONE");
526#define P_CMD(cmd) \
527 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
528 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
529 op &= ~LOCK_##cmd; \
530 }
531
532 P_CMD(SH);
533 P_CMD(EX);
534 P_CMD(NB);
535 P_CMD(UN);
536 P_CMD(MAND);
537 P_CMD(RW);
538 P_CMD(READ);
539 P_CMD(WRITE);
540#undef P_OP
541
542 if (op)
543 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
544
545 return printed;
546}
547
548#define SCA_FLOCK syscall_arg__scnprintf_flock
549
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300550static 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 -0300551{
552 enum syscall_futex_args {
553 SCF_UADDR = (1 << 0),
554 SCF_OP = (1 << 1),
555 SCF_VAL = (1 << 2),
556 SCF_TIMEOUT = (1 << 3),
557 SCF_UADDR2 = (1 << 4),
558 SCF_VAL3 = (1 << 5),
559 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300560 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300561 int cmd = op & FUTEX_CMD_MASK;
562 size_t printed = 0;
563
564 switch (cmd) {
565#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300566 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
567 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
568 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
569 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
570 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
571 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300572 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300573 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
574 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
575 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
576 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
577 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300578 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
579 default: printed = scnprintf(bf, size, "%#x", cmd); break;
580 }
581
582 if (op & FUTEX_PRIVATE_FLAG)
583 printed += scnprintf(bf + printed, size - printed, "|PRIV");
584
585 if (op & FUTEX_CLOCK_REALTIME)
586 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
587
588 return printed;
589}
590
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300591#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
592
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300593static const char *bpf_cmd[] = {
594 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
595 "MAP_GET_NEXT_KEY", "PROG_LOAD",
596};
597static DEFINE_STRARRAY(bpf_cmd);
598
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300599static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
600static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300601
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300602static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
603static DEFINE_STRARRAY(itimers);
604
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300605static const char *keyctl_options[] = {
606 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
607 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
608 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
609 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
610 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
611};
612static DEFINE_STRARRAY(keyctl_options);
613
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300614static const char *whences[] = { "SET", "CUR", "END",
615#ifdef SEEK_DATA
616"DATA",
617#endif
618#ifdef SEEK_HOLE
619"HOLE",
620#endif
621};
622static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300623
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300624static const char *fcntl_cmds[] = {
625 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
626 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
627 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
628 "F_GETOWNER_UIDS",
629};
630static DEFINE_STRARRAY(fcntl_cmds);
631
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300632static const char *rlimit_resources[] = {
633 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
634 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
635 "RTTIME",
636};
637static DEFINE_STRARRAY(rlimit_resources);
638
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300639static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
640static DEFINE_STRARRAY(sighow);
641
David Ahern4f8c1b72013-09-22 19:45:00 -0600642static const char *clockid[] = {
643 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300644 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
645 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600646};
647static DEFINE_STRARRAY(clockid);
648
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300649static const char *socket_families[] = {
650 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
651 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
652 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
653 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
654 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
655 "ALG", "NFC", "VSOCK",
656};
657static DEFINE_STRARRAY(socket_families);
658
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300659#ifndef SOCK_TYPE_MASK
660#define SOCK_TYPE_MASK 0xf
661#endif
662
663static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
664 struct syscall_arg *arg)
665{
666 size_t printed;
667 int type = arg->val,
668 flags = type & ~SOCK_TYPE_MASK;
669
670 type &= SOCK_TYPE_MASK;
671 /*
672 * Can't use a strarray, MIPS may override for ABI reasons.
673 */
674 switch (type) {
675#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
676 P_SK_TYPE(STREAM);
677 P_SK_TYPE(DGRAM);
678 P_SK_TYPE(RAW);
679 P_SK_TYPE(RDM);
680 P_SK_TYPE(SEQPACKET);
681 P_SK_TYPE(DCCP);
682 P_SK_TYPE(PACKET);
683#undef P_SK_TYPE
684 default:
685 printed = scnprintf(bf, size, "%#x", type);
686 }
687
688#define P_SK_FLAG(n) \
689 if (flags & SOCK_##n) { \
690 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
691 flags &= ~SOCK_##n; \
692 }
693
694 P_SK_FLAG(CLOEXEC);
695 P_SK_FLAG(NONBLOCK);
696#undef P_SK_FLAG
697
698 if (flags)
699 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
700
701 return printed;
702}
703
704#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
705
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300706#ifndef MSG_PROBE
707#define MSG_PROBE 0x10
708#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600709#ifndef MSG_WAITFORONE
710#define MSG_WAITFORONE 0x10000
711#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300712#ifndef MSG_SENDPAGE_NOTLAST
713#define MSG_SENDPAGE_NOTLAST 0x20000
714#endif
715#ifndef MSG_FASTOPEN
716#define MSG_FASTOPEN 0x20000000
717#endif
718
719static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
720 struct syscall_arg *arg)
721{
722 int printed = 0, flags = arg->val;
723
724 if (flags == 0)
725 return scnprintf(bf, size, "NONE");
726#define P_MSG_FLAG(n) \
727 if (flags & MSG_##n) { \
728 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
729 flags &= ~MSG_##n; \
730 }
731
732 P_MSG_FLAG(OOB);
733 P_MSG_FLAG(PEEK);
734 P_MSG_FLAG(DONTROUTE);
735 P_MSG_FLAG(TRYHARD);
736 P_MSG_FLAG(CTRUNC);
737 P_MSG_FLAG(PROBE);
738 P_MSG_FLAG(TRUNC);
739 P_MSG_FLAG(DONTWAIT);
740 P_MSG_FLAG(EOR);
741 P_MSG_FLAG(WAITALL);
742 P_MSG_FLAG(FIN);
743 P_MSG_FLAG(SYN);
744 P_MSG_FLAG(CONFIRM);
745 P_MSG_FLAG(RST);
746 P_MSG_FLAG(ERRQUEUE);
747 P_MSG_FLAG(NOSIGNAL);
748 P_MSG_FLAG(MORE);
749 P_MSG_FLAG(WAITFORONE);
750 P_MSG_FLAG(SENDPAGE_NOTLAST);
751 P_MSG_FLAG(FASTOPEN);
752 P_MSG_FLAG(CMSG_CLOEXEC);
753#undef P_MSG_FLAG
754
755 if (flags)
756 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
757
758 return printed;
759}
760
761#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
762
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300763static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
764 struct syscall_arg *arg)
765{
766 size_t printed = 0;
767 int mode = arg->val;
768
769 if (mode == F_OK) /* 0 */
770 return scnprintf(bf, size, "F");
771#define P_MODE(n) \
772 if (mode & n##_OK) { \
773 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
774 mode &= ~n##_OK; \
775 }
776
777 P_MODE(R);
778 P_MODE(W);
779 P_MODE(X);
780#undef P_MODE
781
782 if (mode)
783 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
784
785 return printed;
786}
787
788#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
789
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300790static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
791 struct syscall_arg *arg);
792
793#define SCA_FILENAME syscall_arg__scnprintf_filename
794
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300795static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300796 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300797{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300798 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300799
800 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300801 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300802
803 if (flags == 0)
804 return scnprintf(bf, size, "RDONLY");
805#define P_FLAG(n) \
806 if (flags & O_##n) { \
807 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
808 flags &= ~O_##n; \
809 }
810
811 P_FLAG(APPEND);
812 P_FLAG(ASYNC);
813 P_FLAG(CLOEXEC);
814 P_FLAG(CREAT);
815 P_FLAG(DIRECT);
816 P_FLAG(DIRECTORY);
817 P_FLAG(EXCL);
818 P_FLAG(LARGEFILE);
819 P_FLAG(NOATIME);
820 P_FLAG(NOCTTY);
821#ifdef O_NONBLOCK
822 P_FLAG(NONBLOCK);
823#elif O_NDELAY
824 P_FLAG(NDELAY);
825#endif
826#ifdef O_PATH
827 P_FLAG(PATH);
828#endif
829 P_FLAG(RDWR);
830#ifdef O_DSYNC
831 if ((flags & O_SYNC) == O_SYNC)
832 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
833 else {
834 P_FLAG(DSYNC);
835 }
836#else
837 P_FLAG(SYNC);
838#endif
839 P_FLAG(TRUNC);
840 P_FLAG(WRONLY);
841#undef P_FLAG
842
843 if (flags)
844 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
845
846 return printed;
847}
848
849#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
850
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300851static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
852 struct syscall_arg *arg)
853{
854 int printed = 0, flags = arg->val;
855
856 if (flags == 0)
857 return 0;
858
859#define P_FLAG(n) \
860 if (flags & PERF_FLAG_##n) { \
861 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
862 flags &= ~PERF_FLAG_##n; \
863 }
864
865 P_FLAG(FD_NO_GROUP);
866 P_FLAG(FD_OUTPUT);
867 P_FLAG(PID_CGROUP);
868 P_FLAG(FD_CLOEXEC);
869#undef P_FLAG
870
871 if (flags)
872 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
873
874 return printed;
875}
876
877#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
878
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300879static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
880 struct syscall_arg *arg)
881{
882 int printed = 0, flags = arg->val;
883
884 if (flags == 0)
885 return scnprintf(bf, size, "NONE");
886#define P_FLAG(n) \
887 if (flags & EFD_##n) { \
888 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
889 flags &= ~EFD_##n; \
890 }
891
892 P_FLAG(SEMAPHORE);
893 P_FLAG(CLOEXEC);
894 P_FLAG(NONBLOCK);
895#undef P_FLAG
896
897 if (flags)
898 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
899
900 return printed;
901}
902
903#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
904
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300905static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
906 struct syscall_arg *arg)
907{
908 int printed = 0, flags = arg->val;
909
910#define P_FLAG(n) \
911 if (flags & O_##n) { \
912 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
913 flags &= ~O_##n; \
914 }
915
916 P_FLAG(CLOEXEC);
917 P_FLAG(NONBLOCK);
918#undef P_FLAG
919
920 if (flags)
921 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
922
923 return printed;
924}
925
926#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
927
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300928static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
929{
930 int sig = arg->val;
931
932 switch (sig) {
933#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
934 P_SIGNUM(HUP);
935 P_SIGNUM(INT);
936 P_SIGNUM(QUIT);
937 P_SIGNUM(ILL);
938 P_SIGNUM(TRAP);
939 P_SIGNUM(ABRT);
940 P_SIGNUM(BUS);
941 P_SIGNUM(FPE);
942 P_SIGNUM(KILL);
943 P_SIGNUM(USR1);
944 P_SIGNUM(SEGV);
945 P_SIGNUM(USR2);
946 P_SIGNUM(PIPE);
947 P_SIGNUM(ALRM);
948 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300949 P_SIGNUM(CHLD);
950 P_SIGNUM(CONT);
951 P_SIGNUM(STOP);
952 P_SIGNUM(TSTP);
953 P_SIGNUM(TTIN);
954 P_SIGNUM(TTOU);
955 P_SIGNUM(URG);
956 P_SIGNUM(XCPU);
957 P_SIGNUM(XFSZ);
958 P_SIGNUM(VTALRM);
959 P_SIGNUM(PROF);
960 P_SIGNUM(WINCH);
961 P_SIGNUM(IO);
962 P_SIGNUM(PWR);
963 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000964#ifdef SIGEMT
965 P_SIGNUM(EMT);
966#endif
967#ifdef SIGSTKFLT
968 P_SIGNUM(STKFLT);
969#endif
970#ifdef SIGSWI
971 P_SIGNUM(SWI);
972#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300973 default: break;
974 }
975
976 return scnprintf(bf, size, "%#x", sig);
977}
978
979#define SCA_SIGNUM syscall_arg__scnprintf_signum
980
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300981#if defined(__i386__) || defined(__x86_64__)
982/*
983 * FIXME: Make this available to all arches.
984 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300985#define TCGETS 0x5401
986
987static const char *tioctls[] = {
988 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
989 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
990 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
991 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
992 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
993 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
994 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
995 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
996 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
997 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
998 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
999 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
1000 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
1001 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
1002 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
1003};
1004
1005static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001006#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001007
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001008static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
1009{
1010 int op = arg->val;
1011 size_t printed = 0;
1012
1013 switch (op) {
1014#define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break
1015 P_SECCOMP_SET_MODE_OP(STRICT);
1016 P_SECCOMP_SET_MODE_OP(FILTER);
1017#undef P_SECCOMP_SET_MODE_OP
1018 default: printed = scnprintf(bf, size, "%#x", op); break;
1019 }
1020
1021 return printed;
1022}
1023
1024#define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op
1025
1026static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
1027 struct syscall_arg *arg)
1028{
1029 int printed = 0, flags = arg->val;
1030
1031#define P_FLAG(n) \
1032 if (flags & SECCOMP_FILTER_FLAG_##n) { \
1033 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
1034 flags &= ~SECCOMP_FILTER_FLAG_##n; \
1035 }
1036
1037 P_FLAG(TSYNC);
1038#undef P_FLAG
1039
1040 if (flags)
1041 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
1042
1043 return printed;
1044}
1045
1046#define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
1047
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001048#define STRARRAY(arg, name, array) \
1049 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
1050 .arg_parm = { [arg] = &strarray__##array, }
1051
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001052static struct syscall_fmt {
1053 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001054 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001055 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001056 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001057 bool errmsg;
1058 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001059 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001060} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001061 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001062 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1063 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001064 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -03001065 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001066 { .name = "brk", .hexret = true,
1067 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001068 { .name = "chdir", .errmsg = true,
1069 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1070 { .name = "chmod", .errmsg = true,
1071 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1072 { .name = "chroot", .errmsg = true,
1073 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001074 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001075 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001076 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001077 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001078 { .name = "creat", .errmsg = true,
1079 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001080 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001081 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001082 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001083 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001084 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001085 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001086 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001087 { .name = "eventfd2", .errmsg = true,
1088 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001089 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001090 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1091 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001092 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001093 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001094 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001095 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001096 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001097 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001098 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001099 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001100 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001101 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1102 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001103 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001104 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001105 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001106 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1107 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001108 { .name = "fcntl", .errmsg = true,
1109 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1110 [1] = SCA_STRARRAY, /* cmd */ },
1111 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1112 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001113 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001114 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001115 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1116 [1] = SCA_FLOCK, /* cmd */ }, },
1117 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001118 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001119 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001120 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001121 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001122 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1123 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001124 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001125 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001126 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001127 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001128 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001129 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001130 { .name = "futex", .errmsg = true,
1131 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001132 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001133 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1134 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001135 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001136 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001137 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001138 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001139 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1140 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001141 { .name = "getxattr", .errmsg = true,
1142 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1143 { .name = "inotify_add_watch", .errmsg = true,
1144 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001145 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001146 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001147#if defined(__i386__) || defined(__x86_64__)
1148/*
1149 * FIXME: Make this available to all arches.
1150 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001151 [1] = SCA_STRHEXARRAY, /* cmd */
1152 [2] = SCA_HEX, /* arg */ },
1153 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001154#else
1155 [2] = SCA_HEX, /* arg */ }, },
1156#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001157 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001158 { .name = "kill", .errmsg = true,
1159 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001160 { .name = "lchown", .errmsg = true,
1161 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1162 { .name = "lgetxattr", .errmsg = true,
1163 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001165 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001166 { .name = "listxattr", .errmsg = true,
1167 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001168 { .name = "llistxattr", .errmsg = true,
1169 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1170 { .name = "lremovexattr", .errmsg = true,
1171 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001172 { .name = "lseek", .errmsg = true,
1173 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1174 [2] = SCA_STRARRAY, /* whence */ },
1175 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001176 { .name = "lsetxattr", .errmsg = true,
1177 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001178 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1179 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001180 { .name = "lsxattr", .errmsg = true,
1181 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001182 { .name = "madvise", .errmsg = true,
1183 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1184 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001185 { .name = "mkdir", .errmsg = true,
1186 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001188 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1189 [1] = SCA_FILENAME, /* pathname */ }, },
1190 { .name = "mknod", .errmsg = true,
1191 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001192 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001193 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1194 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001195 { .name = "mlock", .errmsg = true,
1196 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1197 { .name = "mlockall", .errmsg = true,
1198 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001199 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001200 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001201 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001202 [3] = SCA_MMAP_FLAGS, /* flags */
1203 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001204 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001205 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1206 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001207 { .name = "mq_unlink", .errmsg = true,
1208 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001209 { .name = "mremap", .hexret = true,
1210 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001211 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001212 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001213 { .name = "munlock", .errmsg = true,
1214 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001215 { .name = "munmap", .errmsg = true,
1216 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001217 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001218 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001219 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001220 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1221 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001222 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001223 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1224 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001225 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001226 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1227 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001228 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001229 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001230 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001231 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001232 { .name = "perf_event_open", .errmsg = true,
1233 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1234 [2] = SCA_INT, /* cpu */
1235 [3] = SCA_FD, /* group_fd */
1236 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001237 { .name = "pipe2", .errmsg = true,
1238 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001239 { .name = "poll", .errmsg = true, .timeout = true, },
1240 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001241 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001242 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001243 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001244 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001245 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001246 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001247 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001248 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001249 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001250 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001251 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001252 { .name = "readlink", .errmsg = true,
1253 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001254 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001255 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1256 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001257 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001258 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001259 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001260 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1261 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001262 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001263 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1264 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001265 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001266 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1267 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001268 { .name = "removexattr", .errmsg = true,
1269 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001270 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001271 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001272 { .name = "rmdir", .errmsg = true,
1273 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001274 { .name = "rt_sigaction", .errmsg = true,
1275 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001276 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001277 { .name = "rt_sigqueueinfo", .errmsg = true,
1278 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1279 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1280 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -03001281 { .name = "seccomp", .errmsg = true,
1282 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
1283 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001284 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001285 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001286 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1287 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001288 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001289 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1290 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001291 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001292 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1293 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001294 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1295 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001296 { .name = "setxattr", .errmsg = true,
1297 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001298 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001299 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001300 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001301 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1302 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001303 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001304 { .name = "socketpair", .errmsg = true,
1305 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1306 [1] = SCA_SK_TYPE, /* type */ },
1307 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001308 { .name = "stat", .errmsg = true, .alias = "newstat",
1309 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001310 { .name = "statfs", .errmsg = true,
1311 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1312 { .name = "swapoff", .errmsg = true,
1313 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1314 { .name = "swapon", .errmsg = true,
1315 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001316 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001317 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001318 { .name = "tgkill", .errmsg = true,
1319 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1320 { .name = "tkill", .errmsg = true,
1321 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001322 { .name = "truncate", .errmsg = true,
1323 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001324 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001325 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001326 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1327 [1] = SCA_FILENAME, /* pathname */ }, },
1328 { .name = "utime", .errmsg = true,
1329 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001330 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001331 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1332 [1] = SCA_FILENAME, /* filename */ }, },
1333 { .name = "utimes", .errmsg = true,
1334 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001335 { .name = "vmsplice", .errmsg = true,
1336 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001337 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001338 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001339 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001340 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001341};
1342
1343static int syscall_fmt__cmp(const void *name, const void *fmtp)
1344{
1345 const struct syscall_fmt *fmt = fmtp;
1346 return strcmp(name, fmt->name);
1347}
1348
1349static struct syscall_fmt *syscall_fmt__find(const char *name)
1350{
1351 const int nmemb = ARRAY_SIZE(syscall_fmts);
1352 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1353}
1354
1355struct syscall {
1356 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001357 int nr_args;
1358 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001359 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001360 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001361 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001362 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001363 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001364};
1365
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001366static size_t fprintf_duration(unsigned long t, FILE *fp)
1367{
1368 double duration = (double)t / NSEC_PER_MSEC;
1369 size_t printed = fprintf(fp, "(");
1370
1371 if (duration >= 1.0)
1372 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1373 else if (duration >= 0.01)
1374 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1375 else
1376 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001377 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001378}
1379
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001380/**
1381 * filename.ptr: The filename char pointer that will be vfs_getname'd
1382 * filename.entry_str_pos: Where to insert the string translated from
1383 * filename.ptr by the vfs_getname tracepoint/kprobe.
1384 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001385struct thread_trace {
1386 u64 entry_time;
1387 u64 exit_time;
1388 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001389 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001390 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001391 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001392 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001393 struct {
1394 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001395 short int entry_str_pos;
1396 bool pending_open;
1397 unsigned int namelen;
1398 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001399 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001400 struct {
1401 int max;
1402 char **table;
1403 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001404
1405 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001406};
1407
1408static struct thread_trace *thread_trace__new(void)
1409{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001410 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1411
1412 if (ttrace)
1413 ttrace->paths.max = -1;
1414
David Ahernbf2575c2013-10-08 21:26:53 -06001415 ttrace->syscall_stats = intlist__new(NULL);
1416
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001417 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001418}
1419
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001420static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001421{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001422 struct thread_trace *ttrace;
1423
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001424 if (thread == NULL)
1425 goto fail;
1426
Namhyung Kim89dceb22014-10-06 09:46:03 +09001427 if (thread__priv(thread) == NULL)
1428 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001429
Namhyung Kim89dceb22014-10-06 09:46:03 +09001430 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001431 goto fail;
1432
Namhyung Kim89dceb22014-10-06 09:46:03 +09001433 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001434 ++ttrace->nr_events;
1435
1436 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001437fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001438 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001439 "WARNING: not enough memory, dropping samples!\n");
1440 return NULL;
1441}
1442
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001443#define TRACE_PFMAJ (1 << 0)
1444#define TRACE_PFMIN (1 << 1)
1445
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001446static const size_t trace__entry_str_size = 2048;
1447
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001448struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001449 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001450 struct {
1451 int machine;
1452 int open_id;
1453 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001454 struct {
1455 int max;
1456 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001457 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001458 struct perf_evsel *sys_enter,
1459 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001460 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001461 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001462 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001463 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001464 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001465 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001466 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001467 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001468 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001469 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001470 struct {
1471 size_t nr;
1472 int *entries;
1473 } ev_qualifier_ids;
David Ahernbdc89662013-08-28 22:29:53 -06001474 struct intlist *tid_list;
1475 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001476 struct {
1477 size_t nr;
1478 pid_t *entries;
1479 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001480 double duration_filter;
1481 double runtime_ms;
1482 struct {
1483 u64 vfs_getname,
1484 proc_getname;
1485 } stats;
1486 bool not_ev_qualifier;
1487 bool live;
1488 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001489 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001490 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001491 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001492 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001493 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001494 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001495 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001496 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001497 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001498 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001499};
1500
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001501static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001502{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001503 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001504
1505 if (fd > ttrace->paths.max) {
1506 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1507
1508 if (npath == NULL)
1509 return -1;
1510
1511 if (ttrace->paths.max != -1) {
1512 memset(npath + ttrace->paths.max + 1, 0,
1513 (fd - ttrace->paths.max) * sizeof(char *));
1514 } else {
1515 memset(npath, 0, (fd + 1) * sizeof(char *));
1516 }
1517
1518 ttrace->paths.table = npath;
1519 ttrace->paths.max = fd;
1520 }
1521
1522 ttrace->paths.table[fd] = strdup(pathname);
1523
1524 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1525}
1526
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001527static int thread__read_fd_path(struct thread *thread, int fd)
1528{
1529 char linkname[PATH_MAX], pathname[PATH_MAX];
1530 struct stat st;
1531 int ret;
1532
1533 if (thread->pid_ == thread->tid) {
1534 scnprintf(linkname, sizeof(linkname),
1535 "/proc/%d/fd/%d", thread->pid_, fd);
1536 } else {
1537 scnprintf(linkname, sizeof(linkname),
1538 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1539 }
1540
1541 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1542 return -1;
1543
1544 ret = readlink(linkname, pathname, sizeof(pathname));
1545
1546 if (ret < 0 || ret > st.st_size)
1547 return -1;
1548
1549 pathname[ret] = '\0';
1550 return trace__set_fd_pathname(thread, fd, pathname);
1551}
1552
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001553static const char *thread__fd_path(struct thread *thread, int fd,
1554 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001555{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001556 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001557
1558 if (ttrace == NULL)
1559 return NULL;
1560
1561 if (fd < 0)
1562 return NULL;
1563
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001564 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001565 if (!trace->live)
1566 return NULL;
1567 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001568 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001569 return NULL;
1570 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001571
1572 return ttrace->paths.table[fd];
1573}
1574
1575static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1576 struct syscall_arg *arg)
1577{
1578 int fd = arg->val;
1579 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001580 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001581
1582 if (path)
1583 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1584
1585 return printed;
1586}
1587
1588static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1589 struct syscall_arg *arg)
1590{
1591 int fd = arg->val;
1592 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001593 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001594
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001595 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1596 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001597
1598 return printed;
1599}
1600
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001601static void thread__set_filename_pos(struct thread *thread, const char *bf,
1602 unsigned long ptr)
1603{
1604 struct thread_trace *ttrace = thread__priv(thread);
1605
1606 ttrace->filename.ptr = ptr;
1607 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1608}
1609
1610static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1611 struct syscall_arg *arg)
1612{
1613 unsigned long ptr = arg->val;
1614
1615 if (!arg->trace->vfs_getname)
1616 return scnprintf(bf, size, "%#x", ptr);
1617
1618 thread__set_filename_pos(arg->thread, bf, ptr);
1619 return 0;
1620}
1621
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001622static bool trace__filter_duration(struct trace *trace, double t)
1623{
1624 return t < (trace->duration_filter * NSEC_PER_MSEC);
1625}
1626
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001627static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1628{
1629 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1630
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001631 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001632}
1633
Namhyung Kimf15eb532012-10-05 14:02:16 +09001634static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001635static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001636
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001637static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001638{
1639 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001640 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001641}
1642
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001643static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001644 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001645{
1646 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001647 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001648
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001649 if (trace->multiple_threads) {
1650 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001651 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001652 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001653 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001654
1655 return printed;
1656}
1657
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001658static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001659 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001660{
1661 int ret = 0;
1662
1663 switch (event->header.type) {
1664 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001665 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001666 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001667 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001668 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001670 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671 break;
1672 }
1673
1674 return ret;
1675}
1676
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001677static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001679 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680 struct machine *machine)
1681{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001682 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001683 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001684}
1685
1686static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1687{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001688 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001689
1690 if (err)
1691 return err;
1692
David Ahern8fb598e2013-09-28 13:13:00 -06001693 trace->host = machine__new_host();
1694 if (trace->host == NULL)
1695 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001697 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001698 return -errno;
1699
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001700 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001701 evlist->threads, trace__tool_process, false,
1702 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001703 if (err)
1704 symbol__exit();
1705
1706 return err;
1707}
1708
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001709static int syscall__set_arg_fmts(struct syscall *sc)
1710{
1711 struct format_field *field;
1712 int idx = 0;
1713
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001714 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001715 if (sc->arg_scnprintf == NULL)
1716 return -1;
1717
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001718 if (sc->fmt)
1719 sc->arg_parm = sc->fmt->arg_parm;
1720
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001721 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001722 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1723 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1724 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001725 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1726 ++idx;
1727 }
1728
1729 return 0;
1730}
1731
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001732static int trace__read_syscall_info(struct trace *trace, int id)
1733{
1734 char tp_name[128];
1735 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001736 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001737
1738 if (name == NULL)
1739 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001740
1741 if (id > trace->syscalls.max) {
1742 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1743
1744 if (nsyscalls == NULL)
1745 return -1;
1746
1747 if (trace->syscalls.max != -1) {
1748 memset(nsyscalls + trace->syscalls.max + 1, 0,
1749 (id - trace->syscalls.max) * sizeof(*sc));
1750 } else {
1751 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1752 }
1753
1754 trace->syscalls.table = nsyscalls;
1755 trace->syscalls.max = id;
1756 }
1757
1758 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001759 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001760
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001761 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001762
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001763 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001764 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001765
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001766 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001767 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001768 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001769 }
1770
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001771 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001772 return -1;
1773
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001774 sc->args = sc->tp_format->format.fields;
1775 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001776 /*
1777 * We need to check and discard the first variable '__syscall_nr'
1778 * or 'nr' that mean the syscall number. It is needless here.
1779 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1780 */
1781 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001782 sc->args = sc->args->next;
1783 --sc->nr_args;
1784 }
1785
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001786 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1787
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001788 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001789}
1790
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001791static int trace__validate_ev_qualifier(struct trace *trace)
1792{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001793 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001794 struct str_node *pos;
1795
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001796 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1797 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1798 sizeof(trace->ev_qualifier_ids.entries[0]));
1799
1800 if (trace->ev_qualifier_ids.entries == NULL) {
1801 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1802 trace->output);
1803 err = -EINVAL;
1804 goto out;
1805 }
1806
1807 i = 0;
1808
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001809 strlist__for_each(pos, trace->ev_qualifier) {
1810 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001811 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001812
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001813 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001814 if (err == 0) {
1815 fputs("Error:\tInvalid syscall ", trace->output);
1816 err = -EINVAL;
1817 } else {
1818 fputs(", ", trace->output);
1819 }
1820
1821 fputs(sc, trace->output);
1822 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001823
1824 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001825 }
1826
1827 if (err < 0) {
1828 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1829 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001830 zfree(&trace->ev_qualifier_ids.entries);
1831 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001832 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001833out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001834 return err;
1835}
1836
David Ahern55d43bc2015-02-19 15:00:22 -05001837/*
1838 * args is to be interpreted as a series of longs but we need to handle
1839 * 8-byte unaligned accesses. args points to raw_data within the event
1840 * and raw_data is guaranteed to be 8-byte unaligned because it is
1841 * preceded by raw_size which is a u32. So we need to copy args to a temp
1842 * variable to read it. Most notably this avoids extended load instructions
1843 * on unaligned addresses
1844 */
1845
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001846static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001847 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001848 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001849{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001850 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001851 unsigned char *p;
1852 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001853
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001854 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001855 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001856 u8 bit = 1;
1857 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001858 .idx = 0,
1859 .mask = 0,
1860 .trace = trace,
1861 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001862 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001863
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001864 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001865 field = field->next, ++arg.idx, bit <<= 1) {
1866 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001867 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001868
1869 /* special care for unaligned accesses */
1870 p = args + sizeof(unsigned long) * arg.idx;
1871 memcpy(&val, p, sizeof(val));
1872
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001873 /*
1874 * Suppress this argument if its value is zero and
1875 * and we don't have a string associated in an
1876 * strarray for it.
1877 */
David Ahern55d43bc2015-02-19 15:00:22 -05001878 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001879 !(sc->arg_scnprintf &&
1880 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1881 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001882 continue;
1883
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001884 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001885 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001886 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001887 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001888 if (sc->arg_parm)
1889 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001890 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1891 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001892 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001893 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001894 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001895 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001896 }
1897 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001898 int i = 0;
1899
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001900 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001901 /* special care for unaligned accesses */
1902 p = args + sizeof(unsigned long) * i;
1903 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001904 printed += scnprintf(bf + printed, size - printed,
1905 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001906 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001907 ++i;
1908 }
1909 }
1910
1911 return printed;
1912}
1913
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001914typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001915 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001916 struct perf_sample *sample);
1917
1918static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001919 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001920{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001921
1922 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001923
1924 /*
1925 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1926 * before that, leaving at a higher verbosity level till that is
1927 * explained. Reproduced with plain ftrace with:
1928 *
1929 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1930 * grep "NR -1 " /t/trace_pipe
1931 *
1932 * After generating some load on the machine.
1933 */
1934 if (verbose > 1) {
1935 static u64 n;
1936 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1937 id, perf_evsel__name(evsel), ++n);
1938 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001939 return NULL;
1940 }
1941
1942 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1943 trace__read_syscall_info(trace, id))
1944 goto out_cant_read;
1945
1946 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1947 goto out_cant_read;
1948
1949 return &trace->syscalls.table[id];
1950
1951out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001952 if (verbose) {
1953 fprintf(trace->output, "Problems reading syscall %d", id);
1954 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1955 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1956 fputs(" information\n", trace->output);
1957 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001958 return NULL;
1959}
1960
David Ahernbf2575c2013-10-08 21:26:53 -06001961static void thread__update_stats(struct thread_trace *ttrace,
1962 int id, struct perf_sample *sample)
1963{
1964 struct int_node *inode;
1965 struct stats *stats;
1966 u64 duration = 0;
1967
1968 inode = intlist__findnew(ttrace->syscall_stats, id);
1969 if (inode == NULL)
1970 return;
1971
1972 stats = inode->priv;
1973 if (stats == NULL) {
1974 stats = malloc(sizeof(struct stats));
1975 if (stats == NULL)
1976 return;
1977 init_stats(stats);
1978 inode->priv = stats;
1979 }
1980
1981 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1982 duration = sample->time - ttrace->entry_time;
1983
1984 update_stats(stats, duration);
1985}
1986
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001987static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1988{
1989 struct thread_trace *ttrace;
1990 u64 duration;
1991 size_t printed;
1992
1993 if (trace->current == NULL)
1994 return 0;
1995
1996 ttrace = thread__priv(trace->current);
1997
1998 if (!ttrace->entry_pending)
1999 return 0;
2000
2001 duration = sample->time - ttrace->entry_time;
2002
2003 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
2004 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
2005 ttrace->entry_pending = false;
2006
2007 return printed;
2008}
2009
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002010static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002011 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002012 struct perf_sample *sample)
2013{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002014 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002015 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002016 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002017 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002018 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002019 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002020 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002021
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002022 if (sc == NULL)
2023 return -1;
2024
David Ahern8fb598e2013-09-28 13:13:00 -06002025 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002026 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002027 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002028 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002029
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002030 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002031
2032 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002033 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002034 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002035 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002036 }
2037
David Ahern13f22a22015-03-19 12:23:03 -06002038 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03002039 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03002040
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002041 ttrace->entry_time = sample->time;
2042 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002043 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002044
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03002045 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002046 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002047
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03002048 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07002049 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002050 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
2051 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002052 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002053 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002054 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002055 /* See trace__vfs_getname & trace__sys_exit */
2056 ttrace->filename.pending_open = false;
2057 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002058
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002059 if (trace->current != thread) {
2060 thread__put(trace->current);
2061 trace->current = thread__get(thread);
2062 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002063 err = 0;
2064out_put:
2065 thread__put(thread);
2066 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002067}
2068
2069static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002070 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002071 struct perf_sample *sample)
2072{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002073 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002074 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002075 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002076 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002077 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002078 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002079
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002080 if (sc == NULL)
2081 return -1;
2082
David Ahern8fb598e2013-09-28 13:13:00 -06002083 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002084 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002085 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002086 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002087
David Ahernbf2575c2013-10-08 21:26:53 -06002088 if (trace->summary)
2089 thread__update_stats(ttrace, id, sample);
2090
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002091 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002092
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002093 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2094 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2095 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002096 ++trace->stats.vfs_getname;
2097 }
2098
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002099 ttrace->exit_time = sample->time;
2100
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002101 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002102 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002103 if (trace__filter_duration(trace, duration))
2104 goto out;
2105 } else if (trace->duration_filter)
2106 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002107
David Ahernfd2eaba2013-11-12 09:31:15 -07002108 if (trace->summary_only)
2109 goto out;
2110
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002111 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002112
2113 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002114 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002115 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002116 fprintf(trace->output, " ... [");
2117 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2118 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002119 }
2120
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002121 if (sc->fmt == NULL) {
2122signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002123 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002124 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002125 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002126 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2127 *e = audit_errno_to_name(-ret);
2128
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002129 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002130 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002131 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002132 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002133 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002134 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002135 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002136
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002137 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002138out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002139 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002140 err = 0;
2141out_put:
2142 thread__put(thread);
2143 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002144}
2145
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002146static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002147 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002148 struct perf_sample *sample)
2149{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002150 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2151 struct thread_trace *ttrace;
2152 size_t filename_len, entry_str_len, to_move;
2153 ssize_t remaining_space;
2154 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002155 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002156
2157 if (!thread)
2158 goto out;
2159
2160 ttrace = thread__priv(thread);
2161 if (!ttrace)
2162 goto out;
2163
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002164 filename_len = strlen(filename);
2165
2166 if (ttrace->filename.namelen < filename_len) {
2167 char *f = realloc(ttrace->filename.name, filename_len + 1);
2168
2169 if (f == NULL)
2170 goto out;
2171
2172 ttrace->filename.namelen = filename_len;
2173 ttrace->filename.name = f;
2174 }
2175
2176 strcpy(ttrace->filename.name, filename);
2177 ttrace->filename.pending_open = true;
2178
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002179 if (!ttrace->filename.ptr)
2180 goto out;
2181
2182 entry_str_len = strlen(ttrace->entry_str);
2183 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2184 if (remaining_space <= 0)
2185 goto out;
2186
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002187 if (filename_len > (size_t)remaining_space) {
2188 filename += filename_len - remaining_space;
2189 filename_len = remaining_space;
2190 }
2191
2192 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2193 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2194 memmove(pos + filename_len, pos, to_move);
2195 memcpy(pos, filename, filename_len);
2196
2197 ttrace->filename.ptr = 0;
2198 ttrace->filename.entry_str_pos = 0;
2199out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002200 return 0;
2201}
2202
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002203static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002204 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002205 struct perf_sample *sample)
2206{
2207 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2208 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002209 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002210 sample->pid,
2211 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002212 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002213
2214 if (ttrace == NULL)
2215 goto out_dump;
2216
2217 ttrace->runtime_ms += runtime_ms;
2218 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002219 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002220 return 0;
2221
2222out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002223 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002224 evsel->name,
2225 perf_evsel__strval(evsel, sample, "comm"),
2226 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2227 runtime,
2228 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002229 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002230 return 0;
2231}
2232
Wang Nan1d6c9402016-02-26 09:31:55 +00002233static void bpf_output__printer(enum binary_printer_ops op,
2234 unsigned int val, void *extra)
2235{
2236 FILE *output = extra;
2237 unsigned char ch = (unsigned char)val;
2238
2239 switch (op) {
2240 case BINARY_PRINT_CHAR_DATA:
2241 fprintf(output, "%c", isprint(ch) ? ch : '.');
2242 break;
2243 case BINARY_PRINT_DATA_BEGIN:
2244 case BINARY_PRINT_LINE_BEGIN:
2245 case BINARY_PRINT_ADDR:
2246 case BINARY_PRINT_NUM_DATA:
2247 case BINARY_PRINT_NUM_PAD:
2248 case BINARY_PRINT_SEP:
2249 case BINARY_PRINT_CHAR_PAD:
2250 case BINARY_PRINT_LINE_END:
2251 case BINARY_PRINT_DATA_END:
2252 default:
2253 break;
2254 }
2255}
2256
2257static void bpf_output__fprintf(struct trace *trace,
2258 struct perf_sample *sample)
2259{
2260 print_binary(sample->raw_data, sample->raw_size, 8,
2261 bpf_output__printer, trace->output);
2262}
2263
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002264static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2265 union perf_event *event __maybe_unused,
2266 struct perf_sample *sample)
2267{
2268 trace__printf_interrupted_entry(trace, sample);
2269 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002270
2271 if (trace->trace_syscalls)
2272 fprintf(trace->output, "( ): ");
2273
2274 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002275
Wang Nan1d6c9402016-02-26 09:31:55 +00002276 if (perf_evsel__is_bpf_output(evsel)) {
2277 bpf_output__fprintf(trace, sample);
2278 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002279 event_format__fprintf(evsel->tp_format, sample->cpu,
2280 sample->raw_data, sample->raw_size,
2281 trace->output);
2282 }
2283
2284 fprintf(trace->output, ")\n");
2285 return 0;
2286}
2287
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002288static void print_location(FILE *f, struct perf_sample *sample,
2289 struct addr_location *al,
2290 bool print_dso, bool print_sym)
2291{
2292
2293 if ((verbose || print_dso) && al->map)
2294 fprintf(f, "%s@", al->map->dso->long_name);
2295
2296 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002297 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002298 al->addr - al->sym->start);
2299 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002300 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002301 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002302 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002303}
2304
2305static int trace__pgfault(struct trace *trace,
2306 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002307 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002308 struct perf_sample *sample)
2309{
2310 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002311 struct addr_location al;
2312 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002313 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002314 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002315
2316 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002317 ttrace = thread__trace(thread, trace->output);
2318 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002319 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002320
2321 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2322 ttrace->pfmaj++;
2323 else
2324 ttrace->pfmin++;
2325
2326 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002327 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002328
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002329 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002330 sample->ip, &al);
2331
2332 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2333
2334 fprintf(trace->output, "%sfault [",
2335 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2336 "maj" : "min");
2337
2338 print_location(trace->output, sample, &al, false, true);
2339
2340 fprintf(trace->output, "] => ");
2341
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002342 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002343 sample->addr, &al);
2344
2345 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002346 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002347 MAP__FUNCTION, sample->addr, &al);
2348
2349 if (al.map)
2350 map_type = 'x';
2351 else
2352 map_type = '?';
2353 }
2354
2355 print_location(trace->output, sample, &al, true, false);
2356
2357 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002358out:
2359 err = 0;
2360out_put:
2361 thread__put(thread);
2362 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002363}
2364
David Ahernbdc89662013-08-28 22:29:53 -06002365static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2366{
2367 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2368 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2369 return false;
2370
2371 if (trace->pid_list || trace->tid_list)
2372 return true;
2373
2374 return false;
2375}
2376
David Ahern6810fc92013-08-28 22:29:52 -06002377static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002378 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002379 struct perf_sample *sample,
2380 struct perf_evsel *evsel,
2381 struct machine *machine __maybe_unused)
2382{
2383 struct trace *trace = container_of(tool, struct trace, tool);
2384 int err = 0;
2385
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002386 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002387
David Ahernbdc89662013-08-28 22:29:53 -06002388 if (skip_sample(trace, sample))
2389 return 0;
2390
David Ahern4bb09192013-09-04 12:37:43 -06002391 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002392 trace->base_time = sample->time;
2393
David Ahern31605652013-12-04 19:41:41 -07002394 if (handler) {
2395 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002396 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002397 }
David Ahern6810fc92013-08-28 22:29:52 -06002398
2399 return err;
2400}
2401
David Ahernbdc89662013-08-28 22:29:53 -06002402static int parse_target_str(struct trace *trace)
2403{
2404 if (trace->opts.target.pid) {
2405 trace->pid_list = intlist__new(trace->opts.target.pid);
2406 if (trace->pid_list == NULL) {
2407 pr_err("Error parsing process id string\n");
2408 return -EINVAL;
2409 }
2410 }
2411
2412 if (trace->opts.target.tid) {
2413 trace->tid_list = intlist__new(trace->opts.target.tid);
2414 if (trace->tid_list == NULL) {
2415 pr_err("Error parsing thread id string\n");
2416 return -EINVAL;
2417 }
2418 }
2419
2420 return 0;
2421}
2422
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002423static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002424{
2425 unsigned int rec_argc, i, j;
2426 const char **rec_argv;
2427 const char * const record_args[] = {
2428 "record",
2429 "-R",
2430 "-m", "1024",
2431 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002432 };
2433
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002434 const char * const sc_args[] = { "-e", };
2435 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2436 const char * const majpf_args[] = { "-e", "major-faults" };
2437 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2438 const char * const minpf_args[] = { "-e", "minor-faults" };
2439 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2440
David Ahern9aca7f12013-12-04 19:41:39 -07002441 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002442 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2443 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002444 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2445
2446 if (rec_argv == NULL)
2447 return -ENOMEM;
2448
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002449 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002450 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002451 rec_argv[j++] = record_args[i];
2452
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002453 if (trace->trace_syscalls) {
2454 for (i = 0; i < sc_args_nr; i++)
2455 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002456
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002457 /* event string may be different for older kernels - e.g., RHEL6 */
2458 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2459 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2460 else if (is_valid_tracepoint("syscalls:sys_enter"))
2461 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2462 else {
2463 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2464 return -1;
2465 }
David Ahern9aca7f12013-12-04 19:41:39 -07002466 }
David Ahern9aca7f12013-12-04 19:41:39 -07002467
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002468 if (trace->trace_pgfaults & TRACE_PFMAJ)
2469 for (i = 0; i < majpf_args_nr; i++)
2470 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002471
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002472 if (trace->trace_pgfaults & TRACE_PFMIN)
2473 for (i = 0; i < minpf_args_nr; i++)
2474 rec_argv[j++] = minpf_args[i];
2475
2476 for (i = 0; i < (unsigned int)argc; i++)
2477 rec_argv[j++] = argv[i];
2478
2479 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002480}
2481
David Ahernbf2575c2013-10-08 21:26:53 -06002482static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2483
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002484static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002485{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002486 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002487
2488 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002489 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002490
2491 if (perf_evsel__field(evsel, "pathname") == NULL) {
2492 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002493 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002494 }
2495
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002496 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002497 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002498 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002499}
2500
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002501static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2502 u64 config)
2503{
2504 struct perf_evsel *evsel;
2505 struct perf_event_attr attr = {
2506 .type = PERF_TYPE_SOFTWARE,
2507 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002508 };
2509
2510 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002511 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002512
2513 event_attr_init(&attr);
2514
2515 evsel = perf_evsel__new(&attr);
2516 if (!evsel)
2517 return -ENOMEM;
2518
2519 evsel->handler = trace__pgfault;
2520 perf_evlist__add(evlist, evsel);
2521
2522 return 0;
2523}
2524
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002525static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2526{
2527 const u32 type = event->header.type;
2528 struct perf_evsel *evsel;
2529
2530 if (!trace->full_time && trace->base_time == 0)
2531 trace->base_time = sample->time;
2532
2533 if (type != PERF_RECORD_SAMPLE) {
2534 trace__process_event(trace, trace->host, event, sample);
2535 return;
2536 }
2537
2538 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2539 if (evsel == NULL) {
2540 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2541 return;
2542 }
2543
2544 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2545 sample->raw_data == NULL) {
2546 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2547 perf_evsel__name(evsel), sample->tid,
2548 sample->cpu, sample->raw_size);
2549 } else {
2550 tracepoint_handler handler = evsel->handler;
2551 handler(trace, evsel, event, sample);
2552 }
2553}
2554
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002555static int trace__add_syscall_newtp(struct trace *trace)
2556{
2557 int ret = -1;
2558 struct perf_evlist *evlist = trace->evlist;
2559 struct perf_evsel *sys_enter, *sys_exit;
2560
2561 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2562 if (sys_enter == NULL)
2563 goto out;
2564
2565 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2566 goto out_delete_sys_enter;
2567
2568 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2569 if (sys_exit == NULL)
2570 goto out_delete_sys_enter;
2571
2572 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2573 goto out_delete_sys_exit;
2574
2575 perf_evlist__add(evlist, sys_enter);
2576 perf_evlist__add(evlist, sys_exit);
2577
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002578 trace->syscalls.events.sys_enter = sys_enter;
2579 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002580
2581 ret = 0;
2582out:
2583 return ret;
2584
2585out_delete_sys_exit:
2586 perf_evsel__delete_priv(sys_exit);
2587out_delete_sys_enter:
2588 perf_evsel__delete_priv(sys_enter);
2589 goto out;
2590}
2591
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002592static int trace__set_ev_qualifier_filter(struct trace *trace)
2593{
2594 int err = -1;
2595 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2596 trace->ev_qualifier_ids.nr,
2597 trace->ev_qualifier_ids.entries);
2598
2599 if (filter == NULL)
2600 goto out_enomem;
2601
2602 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2603 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2604
2605 free(filter);
2606out:
2607 return err;
2608out_enomem:
2609 errno = ENOMEM;
2610 goto out;
2611}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002612
Namhyung Kimf15eb532012-10-05 14:02:16 +09002613static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002614{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002615 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002616 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002617 int err = -1, i;
2618 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002619 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002620 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002621
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002622 trace->live = true;
2623
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002624 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002625 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002626
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002627 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002628 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002629
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002630 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002631 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002632 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002633 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002634
2635 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2636 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002637 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002638
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002639 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002640 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2641 trace__sched_stat_runtime))
2642 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002643
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002644 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2645 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002646 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002647 goto out_delete_evlist;
2648 }
2649
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002650 err = trace__symbols_init(trace, evlist);
2651 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002652 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002653 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002654 }
2655
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002656 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002657
Namhyung Kimf15eb532012-10-05 14:02:16 +09002658 signal(SIGCHLD, sig_handler);
2659 signal(SIGINT, sig_handler);
2660
2661 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002662 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002663 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002664 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002665 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002666 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002667 }
2668 }
2669
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002670 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002671 if (err < 0)
2672 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002673
Wang Nanba504232016-02-26 09:31:54 +00002674 err = bpf__apply_obj_config();
2675 if (err) {
2676 char errbuf[BUFSIZ];
2677
2678 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2679 pr_err("ERROR: Apply config to BPF failed: %s\n",
2680 errbuf);
2681 goto out_error_open;
2682 }
2683
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002684 /*
2685 * Better not use !target__has_task() here because we need to cover the
2686 * case where no threads were specified in the command line, but a
2687 * workload was, and in that case we will fill in the thread_map when
2688 * we fork the workload in perf_evlist__prepare_workload.
2689 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002690 if (trace->filter_pids.nr > 0)
2691 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002692 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002693 err = perf_evlist__set_filter_pid(evlist, getpid());
2694
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002695 if (err < 0)
2696 goto out_error_mem;
2697
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002698 if (trace->ev_qualifier_ids.nr > 0) {
2699 err = trace__set_ev_qualifier_filter(trace);
2700 if (err < 0)
2701 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002702
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002703 pr_debug("event qualifier tracepoint filter: %s\n",
2704 trace->syscalls.events.sys_exit->filter);
2705 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002706
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002707 err = perf_evlist__apply_filters(evlist, &evsel);
2708 if (err < 0)
2709 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002710
Jiri Olsaf8850372013-11-28 17:57:22 +01002711 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002712 if (err < 0)
2713 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002714
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002715 if (!target__none(&trace->opts.target))
2716 perf_evlist__enable(evlist);
2717
Namhyung Kimf15eb532012-10-05 14:02:16 +09002718 if (forks)
2719 perf_evlist__start_workload(evlist);
2720
Jiri Olsae13798c2015-06-23 00:36:02 +02002721 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002722 evlist->threads->nr > 1 ||
2723 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002724again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002725 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002726
2727 for (i = 0; i < evlist->nr_mmaps; i++) {
2728 union perf_event *event;
2729
2730 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002731 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002732
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002733 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002734
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002735 err = perf_evlist__parse_sample(evlist, event, &sample);
2736 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002737 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002738 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002739 }
2740
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002741 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002742next_event:
2743 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002744
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002745 if (interrupted)
2746 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002747
2748 if (done && !draining) {
2749 perf_evlist__disable(evlist);
2750 draining = true;
2751 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002752 }
2753 }
2754
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002755 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002756 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002757
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002758 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2759 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2760 draining = true;
2761
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002762 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002763 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002764 } else {
2765 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002766 }
2767
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002768out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002769 thread__zput(trace->current);
2770
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002771 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002772
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002773 if (!err) {
2774 if (trace->summary)
2775 trace__fprintf_thread_summary(trace, trace->output);
2776
2777 if (trace->show_tool_stats) {
2778 fprintf(trace->output, "Stats:\n "
2779 " vfs_getname : %" PRIu64 "\n"
2780 " proc_getname: %" PRIu64 "\n",
2781 trace->stats.vfs_getname,
2782 trace->stats.proc_getname);
2783 }
2784 }
David Ahernbf2575c2013-10-08 21:26:53 -06002785
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002786out_delete_evlist:
2787 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002788 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002789 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002790 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002791{
2792 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002793
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002794out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002795 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002796 goto out_error;
2797
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002798out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002799 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002800 goto out_error;
2801
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002802out_error_mmap:
2803 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2804 goto out_error;
2805
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002806out_error_open:
2807 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2808
2809out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002810 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302811 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002812
2813out_error_apply_filters:
2814 fprintf(trace->output,
2815 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2816 evsel->filter, perf_evsel__name(evsel), errno,
2817 strerror_r(errno, errbuf, sizeof(errbuf)));
2818 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002819}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002820out_error_mem:
2821 fprintf(trace->output, "Not enough memory to run!\n");
2822 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002823
2824out_errno:
2825 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2826 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002827}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002828
David Ahern6810fc92013-08-28 22:29:52 -06002829static int trace__replay(struct trace *trace)
2830{
2831 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002832 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002833 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002834 struct perf_data_file file = {
2835 .path = input_name,
2836 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002837 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002838 };
David Ahern6810fc92013-08-28 22:29:52 -06002839 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002840 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002841 int err = -1;
2842
2843 trace->tool.sample = trace__process_sample;
2844 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002845 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002846 trace->tool.comm = perf_event__process_comm;
2847 trace->tool.exit = perf_event__process_exit;
2848 trace->tool.fork = perf_event__process_fork;
2849 trace->tool.attr = perf_event__process_attr;
2850 trace->tool.tracing_data = perf_event__process_tracing_data;
2851 trace->tool.build_id = perf_event__process_build_id;
2852
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002853 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002854 trace->tool.ordering_requires_timestamps = true;
2855
2856 /* add tid to output */
2857 trace->multiple_threads = true;
2858
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002859 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002860 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002861 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002862
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002863 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002864 goto out;
2865
David Ahern8fb598e2013-09-28 13:13:00 -06002866 trace->host = &session->machines.host;
2867
David Ahern6810fc92013-08-28 22:29:52 -06002868 err = perf_session__set_tracepoints_handlers(session, handlers);
2869 if (err)
2870 goto out;
2871
Namhyung Kim003824e2013-11-12 15:25:00 +09002872 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2873 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002874 /* older kernels have syscalls tp versus raw_syscalls */
2875 if (evsel == NULL)
2876 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2877 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002878
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002879 if (evsel &&
2880 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2881 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002882 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2883 goto out;
2884 }
2885
2886 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2887 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002888 if (evsel == NULL)
2889 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2890 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002891 if (evsel &&
2892 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2893 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002894 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002895 goto out;
2896 }
2897
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002898 evlist__for_each(session->evlist, evsel) {
2899 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2900 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2901 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2902 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2903 evsel->handler = trace__pgfault;
2904 }
2905
David Ahernbdc89662013-08-28 22:29:53 -06002906 err = parse_target_str(trace);
2907 if (err != 0)
2908 goto out;
2909
David Ahern6810fc92013-08-28 22:29:52 -06002910 setup_pager();
2911
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002912 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002913 if (err)
2914 pr_err("Failed to process events, error %d", err);
2915
David Ahernbf2575c2013-10-08 21:26:53 -06002916 else if (trace->summary)
2917 trace__fprintf_thread_summary(trace, trace->output);
2918
David Ahern6810fc92013-08-28 22:29:52 -06002919out:
2920 perf_session__delete(session);
2921
2922 return err;
2923}
2924
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002925static size_t trace__fprintf_threads_header(FILE *fp)
2926{
2927 size_t printed;
2928
Pekka Enberg99ff7152013-11-12 16:42:14 +02002929 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002930
2931 return printed;
2932}
2933
2934static size_t thread__dump_stats(struct thread_trace *ttrace,
2935 struct trace *trace, FILE *fp)
2936{
2937 struct stats *stats;
2938 size_t printed = 0;
2939 struct syscall *sc;
2940 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2941
2942 if (inode == NULL)
2943 return 0;
2944
2945 printed += fprintf(fp, "\n");
2946
Milian Wolff834fd462015-08-06 11:24:29 +02002947 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2948 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2949 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002950
David Ahernbf2575c2013-10-08 21:26:53 -06002951 /* each int_node is a syscall */
2952 while (inode) {
2953 stats = inode->priv;
2954 if (stats) {
2955 double min = (double)(stats->min) / NSEC_PER_MSEC;
2956 double max = (double)(stats->max) / NSEC_PER_MSEC;
2957 double avg = avg_stats(stats);
2958 double pct;
2959 u64 n = (u64) stats->n;
2960
2961 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2962 avg /= NSEC_PER_MSEC;
2963
2964 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002965 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002966 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2967 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002968 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002969 }
2970
2971 inode = intlist__next(inode);
2972 }
2973
2974 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002975
2976 return printed;
2977}
2978
David Ahern896cbb52013-09-28 13:12:59 -06002979/* struct used to pass data to per-thread function */
2980struct summary_data {
2981 FILE *fp;
2982 struct trace *trace;
2983 size_t printed;
2984};
2985
2986static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2987{
2988 struct summary_data *data = priv;
2989 FILE *fp = data->fp;
2990 size_t printed = data->printed;
2991 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002992 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002993 double ratio;
2994
2995 if (ttrace == NULL)
2996 return 0;
2997
2998 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2999
Pekka Enberg15e65c62013-11-14 18:43:30 +02003000 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003001 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02003002 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04003003 if (ttrace->pfmaj)
3004 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
3005 if (ttrace->pfmin)
3006 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02003007 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06003008 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06003009
3010 data->printed += printed;
3011
3012 return 0;
3013}
3014
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003015static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
3016{
David Ahern896cbb52013-09-28 13:12:59 -06003017 struct summary_data data = {
3018 .fp = fp,
3019 .trace = trace
3020 };
3021 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003022
David Ahern896cbb52013-09-28 13:12:59 -06003023 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003024
David Ahern896cbb52013-09-28 13:12:59 -06003025 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003026}
3027
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003028static int trace__set_duration(const struct option *opt, const char *str,
3029 int unset __maybe_unused)
3030{
3031 struct trace *trace = opt->value;
3032
3033 trace->duration_filter = atof(str);
3034 return 0;
3035}
3036
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08003037static int trace__set_filter_pids(const struct option *opt, const char *str,
3038 int unset __maybe_unused)
3039{
3040 int ret = -1;
3041 size_t i;
3042 struct trace *trace = opt->value;
3043 /*
3044 * FIXME: introduce a intarray class, plain parse csv and create a
3045 * { int nr, int entries[] } struct...
3046 */
3047 struct intlist *list = intlist__new(str);
3048
3049 if (list == NULL)
3050 return -1;
3051
3052 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3053 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3054
3055 if (trace->filter_pids.entries == NULL)
3056 goto out;
3057
3058 trace->filter_pids.entries[0] = getpid();
3059
3060 for (i = 1; i < trace->filter_pids.nr; ++i)
3061 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3062
3063 intlist__delete(list);
3064 ret = 0;
3065out:
3066 return ret;
3067}
3068
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003069static int trace__open_output(struct trace *trace, const char *filename)
3070{
3071 struct stat st;
3072
3073 if (!stat(filename, &st) && st.st_size) {
3074 char oldname[PATH_MAX];
3075
3076 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3077 unlink(oldname);
3078 rename(filename, oldname);
3079 }
3080
3081 trace->output = fopen(filename, "w");
3082
3083 return trace->output == NULL ? -errno : 0;
3084}
3085
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003086static int parse_pagefaults(const struct option *opt, const char *str,
3087 int unset __maybe_unused)
3088{
3089 int *trace_pgfaults = opt->value;
3090
3091 if (strcmp(str, "all") == 0)
3092 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3093 else if (strcmp(str, "maj") == 0)
3094 *trace_pgfaults |= TRACE_PFMAJ;
3095 else if (strcmp(str, "min") == 0)
3096 *trace_pgfaults |= TRACE_PFMIN;
3097 else
3098 return -1;
3099
3100 return 0;
3101}
3102
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003103static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3104{
3105 struct perf_evsel *evsel;
3106
3107 evlist__for_each(evlist, evsel)
3108 evsel->handler = handler;
3109}
3110
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003111int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3112{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003113 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003114 "perf trace [<options>] [<command>]",
3115 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003116 "perf trace record [<options>] [<command>]",
3117 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003118 NULL
3119 };
3120 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003121 .audit = {
3122 .machine = audit_detect_machine(),
3123 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3124 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003125 .syscalls = {
3126 . max = -1,
3127 },
3128 .opts = {
3129 .target = {
3130 .uid = UINT_MAX,
3131 .uses_mmap = true,
3132 },
3133 .user_freq = UINT_MAX,
3134 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003135 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003136 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003137 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003138 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003139 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003140 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003141 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003142 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003143 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003144 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003145 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003146 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3147 "event selector. use 'perf list' to list available events",
3148 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003149 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3150 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003151 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003152 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003153 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003154 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003155 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3156 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003157 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003158 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003159 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3160 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003161 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003162 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003163 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003164 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003165 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003166 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003167 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3168 "number of mmap data pages",
3169 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003170 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003171 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003172 OPT_CALLBACK(0, "duration", &trace, "float",
3173 "show only events with duration > N.M ms",
3174 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003175 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003176 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003177 OPT_BOOLEAN('T', "time", &trace.full_time,
3178 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003179 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3180 "Show only syscall summary with statistics"),
3181 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3182 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003183 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3184 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003185 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003186 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003187 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3188 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003189 OPT_END()
3190 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003191 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003192 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003193 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003194
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003195 signal(SIGSEGV, sighandler_dump_stack);
3196 signal(SIGFPE, sighandler_dump_stack);
3197
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003198 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003199
3200 if (trace.evlist == NULL) {
3201 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003202 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003203 goto out;
3204 }
3205
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003206 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3207 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003208
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003209 if (trace.trace_pgfaults) {
3210 trace.opts.sample_address = true;
3211 trace.opts.sample_time = true;
3212 }
3213
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003214 if (trace.evlist->nr_entries > 0)
3215 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3216
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003217 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3218 return trace__record(&trace, argc-1, &argv[1]);
3219
3220 /* summary_only implies summary option, but don't overwrite summary if set */
3221 if (trace.summary_only)
3222 trace.summary = trace.summary_only;
3223
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003224 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3225 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003226 pr_err("Please specify something to trace.\n");
3227 return -1;
3228 }
3229
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003230 if (output_name != NULL) {
3231 err = trace__open_output(&trace, output_name);
3232 if (err < 0) {
3233 perror("failed to create output file");
3234 goto out;
3235 }
3236 }
3237
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003238 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003239 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003240 struct strlist_config slist_config = {
3241 .dirname = system_path(STRACE_GROUPS_DIR),
3242 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003243
3244 trace.not_ev_qualifier = *s == '!';
3245 if (trace.not_ev_qualifier)
3246 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003247 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003248 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003249 fputs("Not enough memory to parse event qualifier",
3250 trace.output);
3251 err = -ENOMEM;
3252 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003253 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003254
3255 err = trace__validate_ev_qualifier(&trace);
3256 if (err)
3257 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003258 }
3259
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003260 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003261 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003262 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003263 fprintf(trace.output, "%s", bf);
3264 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003265 }
3266
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003267 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003268 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003269 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003270 fprintf(trace.output, "%s", bf);
3271 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003272 }
3273
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003274 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003275 trace.opts.target.system_wide = true;
3276
David Ahern6810fc92013-08-28 22:29:52 -06003277 if (input_name)
3278 err = trace__replay(&trace);
3279 else
3280 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003281
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003282out_close:
3283 if (output_name != NULL)
3284 fclose(trace.output);
3285out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003286 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003287}