blob: 4e3abba03062f3e84cfbdea5ca2c07adc641b35b [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>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030020#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030021#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030022#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030023#include "util/evlist.h"
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -030024#include "util/exec_cmd.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030025#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060026#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030027#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030028#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030029#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060030#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030031#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060032#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010033#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070034#include "util/parse-events.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030035
36#include <libaudit.h>
37#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030038#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030039#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Ingo Molnar456857b2013-09-12 15:29:00 +020041/* For older distros: */
42#ifndef MAP_STACK
43# define MAP_STACK 0x20000
44#endif
45
46#ifndef MADV_HWPOISON
47# define MADV_HWPOISON 100
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -030048
Ingo Molnar456857b2013-09-12 15:29:00 +020049#endif
50
51#ifndef MADV_MERGEABLE
52# define MADV_MERGEABLE 12
53#endif
54
55#ifndef MADV_UNMERGEABLE
56# define MADV_UNMERGEABLE 13
57#endif
58
Ben Hutchings79d26a62014-02-06 01:00:35 +000059#ifndef EFD_SEMAPHORE
60# define EFD_SEMAPHORE 1
61#endif
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef EFD_NONBLOCK
64# define EFD_NONBLOCK 00004000
65#endif
66
67#ifndef EFD_CLOEXEC
68# define EFD_CLOEXEC 02000000
69#endif
70
71#ifndef O_CLOEXEC
72# define O_CLOEXEC 02000000
73#endif
74
75#ifndef SOCK_DCCP
76# define SOCK_DCCP 6
77#endif
78
79#ifndef SOCK_CLOEXEC
80# define SOCK_CLOEXEC 02000000
81#endif
82
83#ifndef SOCK_NONBLOCK
84# define SOCK_NONBLOCK 00004000
85#endif
86
87#ifndef MSG_CMSG_CLOEXEC
88# define MSG_CMSG_CLOEXEC 0x40000000
89#endif
90
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -030091#ifndef PERF_FLAG_FD_NO_GROUP
92# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
93#endif
94
95#ifndef PERF_FLAG_FD_OUTPUT
96# define PERF_FLAG_FD_OUTPUT (1UL << 1)
97#endif
98
99#ifndef PERF_FLAG_PID_CGROUP
100# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
101#endif
102
103#ifndef PERF_FLAG_FD_CLOEXEC
104# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
105#endif
106
107
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300108struct tp_field {
109 int offset;
110 union {
111 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
112 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
113 };
114};
115
116#define TP_UINT_FIELD(bits) \
117static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
118{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500119 u##bits value; \
120 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
121 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300122}
123
124TP_UINT_FIELD(8);
125TP_UINT_FIELD(16);
126TP_UINT_FIELD(32);
127TP_UINT_FIELD(64);
128
129#define TP_UINT_FIELD__SWAPPED(bits) \
130static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
131{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500132 u##bits value; \
133 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300134 return bswap_##bits(value);\
135}
136
137TP_UINT_FIELD__SWAPPED(16);
138TP_UINT_FIELD__SWAPPED(32);
139TP_UINT_FIELD__SWAPPED(64);
140
141static int tp_field__init_uint(struct tp_field *field,
142 struct format_field *format_field,
143 bool needs_swap)
144{
145 field->offset = format_field->offset;
146
147 switch (format_field->size) {
148 case 1:
149 field->integer = tp_field__u8;
150 break;
151 case 2:
152 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
153 break;
154 case 4:
155 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
156 break;
157 case 8:
158 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
159 break;
160 default:
161 return -1;
162 }
163
164 return 0;
165}
166
167static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
168{
169 return sample->raw_data + field->offset;
170}
171
172static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
173{
174 field->offset = format_field->offset;
175 field->pointer = tp_field__ptr;
176 return 0;
177}
178
179struct syscall_tp {
180 struct tp_field id;
181 union {
182 struct tp_field args, ret;
183 };
184};
185
186static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
187 struct tp_field *field,
188 const char *name)
189{
190 struct format_field *format_field = perf_evsel__field(evsel, name);
191
192 if (format_field == NULL)
193 return -1;
194
195 return tp_field__init_uint(field, format_field, evsel->needs_swap);
196}
197
198#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
199 ({ struct syscall_tp *sc = evsel->priv;\
200 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
201
202static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
203 struct tp_field *field,
204 const char *name)
205{
206 struct format_field *format_field = perf_evsel__field(evsel, name);
207
208 if (format_field == NULL)
209 return -1;
210
211 return tp_field__init_ptr(field, format_field);
212}
213
214#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
215 ({ struct syscall_tp *sc = evsel->priv;\
216 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
217
218static void perf_evsel__delete_priv(struct perf_evsel *evsel)
219{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300220 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300221 perf_evsel__delete(evsel);
222}
223
Namhyung Kim96695d42013-11-12 08:51:45 -0300224static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
225{
226 evsel->priv = malloc(sizeof(struct syscall_tp));
227 if (evsel->priv != NULL) {
228 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
229 goto out_delete;
230
231 evsel->handler = handler;
232 return 0;
233 }
234
235 return -ENOMEM;
236
237out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300238 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300239 return -ENOENT;
240}
241
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300242static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300243{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245
David Ahern9aca7f12013-12-04 19:41:39 -0700246 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
247 if (evsel == NULL)
248 evsel = perf_evsel__newtp("syscalls", direction);
249
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300250 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300251 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300252 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300253 }
254
255 return evsel;
256
257out_delete:
258 perf_evsel__delete_priv(evsel);
259 return NULL;
260}
261
262#define perf_evsel__sc_tp_uint(evsel, name, sample) \
263 ({ struct syscall_tp *fields = evsel->priv; \
264 fields->name.integer(&fields->name, sample); })
265
266#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
267 ({ struct syscall_tp *fields = evsel->priv; \
268 fields->name.pointer(&fields->name, sample); })
269
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300270struct syscall_arg {
271 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300272 struct thread *thread;
273 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300274 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300275 u8 idx;
276 u8 mask;
277};
278
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300279struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300280 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300281 int nr_entries;
282 const char **entries;
283};
284
285#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
286 .nr_entries = ARRAY_SIZE(array), \
287 .entries = array, \
288}
289
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300290#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
291 .offset = off, \
292 .nr_entries = ARRAY_SIZE(array), \
293 .entries = array, \
294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300301 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302
303 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300304 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305
306 return scnprintf(bf, size, "%s", sa->entries[idx]);
307}
308
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300309static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
310 struct syscall_arg *arg)
311{
312 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
313}
314
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300315#define SCA_STRARRAY syscall_arg__scnprintf_strarray
316
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300317#if defined(__i386__) || defined(__x86_64__)
318/*
319 * FIXME: Make this available to all arches as soon as the ioctl beautifier
320 * gets rewritten to support all arches.
321 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300322static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
323 struct syscall_arg *arg)
324{
325 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
326}
327
328#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300329#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300330
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300331static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
332 struct syscall_arg *arg);
333
334#define SCA_FD syscall_arg__scnprintf_fd
335
336static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
337 struct syscall_arg *arg)
338{
339 int fd = arg->val;
340
341 if (fd == AT_FDCWD)
342 return scnprintf(bf, size, "CWD");
343
344 return syscall_arg__scnprintf_fd(bf, size, arg);
345}
346
347#define SCA_FDAT syscall_arg__scnprintf_fd_at
348
349static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
350 struct syscall_arg *arg);
351
352#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
353
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300354static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300356{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300357 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300358}
359
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300360#define SCA_HEX syscall_arg__scnprintf_hex
361
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300362static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
363 struct syscall_arg *arg)
364{
365 return scnprintf(bf, size, "%d", arg->val);
366}
367
368#define SCA_INT syscall_arg__scnprintf_int
369
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300370static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300371 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300372{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300373 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300374
375 if (prot == PROT_NONE)
376 return scnprintf(bf, size, "NONE");
377#define P_MMAP_PROT(n) \
378 if (prot & PROT_##n) { \
379 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
380 prot &= ~PROT_##n; \
381 }
382
383 P_MMAP_PROT(EXEC);
384 P_MMAP_PROT(READ);
385 P_MMAP_PROT(WRITE);
386#ifdef PROT_SEM
387 P_MMAP_PROT(SEM);
388#endif
389 P_MMAP_PROT(GROWSDOWN);
390 P_MMAP_PROT(GROWSUP);
391#undef P_MMAP_PROT
392
393 if (prot)
394 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
395
396 return printed;
397}
398
399#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
400
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300401static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300402 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300403{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300404 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300405
406#define P_MMAP_FLAG(n) \
407 if (flags & MAP_##n) { \
408 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
409 flags &= ~MAP_##n; \
410 }
411
412 P_MMAP_FLAG(SHARED);
413 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400414#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300415 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400416#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300417 P_MMAP_FLAG(ANONYMOUS);
418 P_MMAP_FLAG(DENYWRITE);
419 P_MMAP_FLAG(EXECUTABLE);
420 P_MMAP_FLAG(FILE);
421 P_MMAP_FLAG(FIXED);
422 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600423#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300424 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600425#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300426 P_MMAP_FLAG(LOCKED);
427 P_MMAP_FLAG(NONBLOCK);
428 P_MMAP_FLAG(NORESERVE);
429 P_MMAP_FLAG(POPULATE);
430 P_MMAP_FLAG(STACK);
431#ifdef MAP_UNINITIALIZED
432 P_MMAP_FLAG(UNINITIALIZED);
433#endif
434#undef P_MMAP_FLAG
435
436 if (flags)
437 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
438
439 return printed;
440}
441
442#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
443
Alex Snast86998dd2014-08-13 18:42:40 +0300444static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
445 struct syscall_arg *arg)
446{
447 int printed = 0, flags = arg->val;
448
449#define P_MREMAP_FLAG(n) \
450 if (flags & MREMAP_##n) { \
451 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
452 flags &= ~MREMAP_##n; \
453 }
454
455 P_MREMAP_FLAG(MAYMOVE);
456#ifdef MREMAP_FIXED
457 P_MREMAP_FLAG(FIXED);
458#endif
459#undef P_MREMAP_FLAG
460
461 if (flags)
462 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
463
464 return printed;
465}
466
467#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
468
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300469static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300470 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300471{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300472 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300473
474 switch (behavior) {
475#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
476 P_MADV_BHV(NORMAL);
477 P_MADV_BHV(RANDOM);
478 P_MADV_BHV(SEQUENTIAL);
479 P_MADV_BHV(WILLNEED);
480 P_MADV_BHV(DONTNEED);
481 P_MADV_BHV(REMOVE);
482 P_MADV_BHV(DONTFORK);
483 P_MADV_BHV(DOFORK);
484 P_MADV_BHV(HWPOISON);
485#ifdef MADV_SOFT_OFFLINE
486 P_MADV_BHV(SOFT_OFFLINE);
487#endif
488 P_MADV_BHV(MERGEABLE);
489 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600490#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300491 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600492#endif
493#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300494 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600495#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300496#ifdef MADV_DONTDUMP
497 P_MADV_BHV(DONTDUMP);
498#endif
499#ifdef MADV_DODUMP
500 P_MADV_BHV(DODUMP);
501#endif
502#undef P_MADV_PHV
503 default: break;
504 }
505
506 return scnprintf(bf, size, "%#x", behavior);
507}
508
509#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
510
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300511static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
512 struct syscall_arg *arg)
513{
514 int printed = 0, op = arg->val;
515
516 if (op == 0)
517 return scnprintf(bf, size, "NONE");
518#define P_CMD(cmd) \
519 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
520 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
521 op &= ~LOCK_##cmd; \
522 }
523
524 P_CMD(SH);
525 P_CMD(EX);
526 P_CMD(NB);
527 P_CMD(UN);
528 P_CMD(MAND);
529 P_CMD(RW);
530 P_CMD(READ);
531 P_CMD(WRITE);
532#undef P_OP
533
534 if (op)
535 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
536
537 return printed;
538}
539
540#define SCA_FLOCK syscall_arg__scnprintf_flock
541
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300542static 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 -0300543{
544 enum syscall_futex_args {
545 SCF_UADDR = (1 << 0),
546 SCF_OP = (1 << 1),
547 SCF_VAL = (1 << 2),
548 SCF_TIMEOUT = (1 << 3),
549 SCF_UADDR2 = (1 << 4),
550 SCF_VAL3 = (1 << 5),
551 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300552 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300553 int cmd = op & FUTEX_CMD_MASK;
554 size_t printed = 0;
555
556 switch (cmd) {
557#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300558 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
559 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
560 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
561 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
562 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
563 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300564 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300565 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
566 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
567 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
568 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
569 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300570 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
571 default: printed = scnprintf(bf, size, "%#x", cmd); break;
572 }
573
574 if (op & FUTEX_PRIVATE_FLAG)
575 printed += scnprintf(bf + printed, size - printed, "|PRIV");
576
577 if (op & FUTEX_CLOCK_REALTIME)
578 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
579
580 return printed;
581}
582
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300583#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
584
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300585static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
586static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300587
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300588static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
589static DEFINE_STRARRAY(itimers);
590
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300591static const char *keyctl_options[] = {
592 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
593 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
594 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
595 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
596 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
597};
598static DEFINE_STRARRAY(keyctl_options);
599
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300600static const char *whences[] = { "SET", "CUR", "END",
601#ifdef SEEK_DATA
602"DATA",
603#endif
604#ifdef SEEK_HOLE
605"HOLE",
606#endif
607};
608static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300609
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300610static const char *fcntl_cmds[] = {
611 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
612 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
613 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
614 "F_GETOWNER_UIDS",
615};
616static DEFINE_STRARRAY(fcntl_cmds);
617
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300618static const char *rlimit_resources[] = {
619 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
620 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
621 "RTTIME",
622};
623static DEFINE_STRARRAY(rlimit_resources);
624
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300625static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
626static DEFINE_STRARRAY(sighow);
627
David Ahern4f8c1b72013-09-22 19:45:00 -0600628static const char *clockid[] = {
629 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300630 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
631 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600632};
633static DEFINE_STRARRAY(clockid);
634
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300635static const char *socket_families[] = {
636 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
637 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
638 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
639 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
640 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
641 "ALG", "NFC", "VSOCK",
642};
643static DEFINE_STRARRAY(socket_families);
644
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300645#ifndef SOCK_TYPE_MASK
646#define SOCK_TYPE_MASK 0xf
647#endif
648
649static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
650 struct syscall_arg *arg)
651{
652 size_t printed;
653 int type = arg->val,
654 flags = type & ~SOCK_TYPE_MASK;
655
656 type &= SOCK_TYPE_MASK;
657 /*
658 * Can't use a strarray, MIPS may override for ABI reasons.
659 */
660 switch (type) {
661#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
662 P_SK_TYPE(STREAM);
663 P_SK_TYPE(DGRAM);
664 P_SK_TYPE(RAW);
665 P_SK_TYPE(RDM);
666 P_SK_TYPE(SEQPACKET);
667 P_SK_TYPE(DCCP);
668 P_SK_TYPE(PACKET);
669#undef P_SK_TYPE
670 default:
671 printed = scnprintf(bf, size, "%#x", type);
672 }
673
674#define P_SK_FLAG(n) \
675 if (flags & SOCK_##n) { \
676 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
677 flags &= ~SOCK_##n; \
678 }
679
680 P_SK_FLAG(CLOEXEC);
681 P_SK_FLAG(NONBLOCK);
682#undef P_SK_FLAG
683
684 if (flags)
685 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
686
687 return printed;
688}
689
690#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
691
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300692#ifndef MSG_PROBE
693#define MSG_PROBE 0x10
694#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600695#ifndef MSG_WAITFORONE
696#define MSG_WAITFORONE 0x10000
697#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300698#ifndef MSG_SENDPAGE_NOTLAST
699#define MSG_SENDPAGE_NOTLAST 0x20000
700#endif
701#ifndef MSG_FASTOPEN
702#define MSG_FASTOPEN 0x20000000
703#endif
704
705static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
706 struct syscall_arg *arg)
707{
708 int printed = 0, flags = arg->val;
709
710 if (flags == 0)
711 return scnprintf(bf, size, "NONE");
712#define P_MSG_FLAG(n) \
713 if (flags & MSG_##n) { \
714 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
715 flags &= ~MSG_##n; \
716 }
717
718 P_MSG_FLAG(OOB);
719 P_MSG_FLAG(PEEK);
720 P_MSG_FLAG(DONTROUTE);
721 P_MSG_FLAG(TRYHARD);
722 P_MSG_FLAG(CTRUNC);
723 P_MSG_FLAG(PROBE);
724 P_MSG_FLAG(TRUNC);
725 P_MSG_FLAG(DONTWAIT);
726 P_MSG_FLAG(EOR);
727 P_MSG_FLAG(WAITALL);
728 P_MSG_FLAG(FIN);
729 P_MSG_FLAG(SYN);
730 P_MSG_FLAG(CONFIRM);
731 P_MSG_FLAG(RST);
732 P_MSG_FLAG(ERRQUEUE);
733 P_MSG_FLAG(NOSIGNAL);
734 P_MSG_FLAG(MORE);
735 P_MSG_FLAG(WAITFORONE);
736 P_MSG_FLAG(SENDPAGE_NOTLAST);
737 P_MSG_FLAG(FASTOPEN);
738 P_MSG_FLAG(CMSG_CLOEXEC);
739#undef P_MSG_FLAG
740
741 if (flags)
742 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
743
744 return printed;
745}
746
747#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
748
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300749static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
750 struct syscall_arg *arg)
751{
752 size_t printed = 0;
753 int mode = arg->val;
754
755 if (mode == F_OK) /* 0 */
756 return scnprintf(bf, size, "F");
757#define P_MODE(n) \
758 if (mode & n##_OK) { \
759 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
760 mode &= ~n##_OK; \
761 }
762
763 P_MODE(R);
764 P_MODE(W);
765 P_MODE(X);
766#undef P_MODE
767
768 if (mode)
769 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
770
771 return printed;
772}
773
774#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
775
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300776static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
777 struct syscall_arg *arg);
778
779#define SCA_FILENAME syscall_arg__scnprintf_filename
780
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300781static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300782 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300783{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300784 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300785
786 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300787 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300788
789 if (flags == 0)
790 return scnprintf(bf, size, "RDONLY");
791#define P_FLAG(n) \
792 if (flags & O_##n) { \
793 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
794 flags &= ~O_##n; \
795 }
796
797 P_FLAG(APPEND);
798 P_FLAG(ASYNC);
799 P_FLAG(CLOEXEC);
800 P_FLAG(CREAT);
801 P_FLAG(DIRECT);
802 P_FLAG(DIRECTORY);
803 P_FLAG(EXCL);
804 P_FLAG(LARGEFILE);
805 P_FLAG(NOATIME);
806 P_FLAG(NOCTTY);
807#ifdef O_NONBLOCK
808 P_FLAG(NONBLOCK);
809#elif O_NDELAY
810 P_FLAG(NDELAY);
811#endif
812#ifdef O_PATH
813 P_FLAG(PATH);
814#endif
815 P_FLAG(RDWR);
816#ifdef O_DSYNC
817 if ((flags & O_SYNC) == O_SYNC)
818 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
819 else {
820 P_FLAG(DSYNC);
821 }
822#else
823 P_FLAG(SYNC);
824#endif
825 P_FLAG(TRUNC);
826 P_FLAG(WRONLY);
827#undef P_FLAG
828
829 if (flags)
830 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
831
832 return printed;
833}
834
835#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
836
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300837static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
838 struct syscall_arg *arg)
839{
840 int printed = 0, flags = arg->val;
841
842 if (flags == 0)
843 return 0;
844
845#define P_FLAG(n) \
846 if (flags & PERF_FLAG_##n) { \
847 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
848 flags &= ~PERF_FLAG_##n; \
849 }
850
851 P_FLAG(FD_NO_GROUP);
852 P_FLAG(FD_OUTPUT);
853 P_FLAG(PID_CGROUP);
854 P_FLAG(FD_CLOEXEC);
855#undef P_FLAG
856
857 if (flags)
858 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
859
860 return printed;
861}
862
863#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
864
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300865static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
866 struct syscall_arg *arg)
867{
868 int printed = 0, flags = arg->val;
869
870 if (flags == 0)
871 return scnprintf(bf, size, "NONE");
872#define P_FLAG(n) \
873 if (flags & EFD_##n) { \
874 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
875 flags &= ~EFD_##n; \
876 }
877
878 P_FLAG(SEMAPHORE);
879 P_FLAG(CLOEXEC);
880 P_FLAG(NONBLOCK);
881#undef P_FLAG
882
883 if (flags)
884 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
885
886 return printed;
887}
888
889#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
890
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300891static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
892 struct syscall_arg *arg)
893{
894 int printed = 0, flags = arg->val;
895
896#define P_FLAG(n) \
897 if (flags & O_##n) { \
898 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
899 flags &= ~O_##n; \
900 }
901
902 P_FLAG(CLOEXEC);
903 P_FLAG(NONBLOCK);
904#undef P_FLAG
905
906 if (flags)
907 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
908
909 return printed;
910}
911
912#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
913
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300914static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
915{
916 int sig = arg->val;
917
918 switch (sig) {
919#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
920 P_SIGNUM(HUP);
921 P_SIGNUM(INT);
922 P_SIGNUM(QUIT);
923 P_SIGNUM(ILL);
924 P_SIGNUM(TRAP);
925 P_SIGNUM(ABRT);
926 P_SIGNUM(BUS);
927 P_SIGNUM(FPE);
928 P_SIGNUM(KILL);
929 P_SIGNUM(USR1);
930 P_SIGNUM(SEGV);
931 P_SIGNUM(USR2);
932 P_SIGNUM(PIPE);
933 P_SIGNUM(ALRM);
934 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300935 P_SIGNUM(CHLD);
936 P_SIGNUM(CONT);
937 P_SIGNUM(STOP);
938 P_SIGNUM(TSTP);
939 P_SIGNUM(TTIN);
940 P_SIGNUM(TTOU);
941 P_SIGNUM(URG);
942 P_SIGNUM(XCPU);
943 P_SIGNUM(XFSZ);
944 P_SIGNUM(VTALRM);
945 P_SIGNUM(PROF);
946 P_SIGNUM(WINCH);
947 P_SIGNUM(IO);
948 P_SIGNUM(PWR);
949 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000950#ifdef SIGEMT
951 P_SIGNUM(EMT);
952#endif
953#ifdef SIGSTKFLT
954 P_SIGNUM(STKFLT);
955#endif
956#ifdef SIGSWI
957 P_SIGNUM(SWI);
958#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300959 default: break;
960 }
961
962 return scnprintf(bf, size, "%#x", sig);
963}
964
965#define SCA_SIGNUM syscall_arg__scnprintf_signum
966
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300967#if defined(__i386__) || defined(__x86_64__)
968/*
969 * FIXME: Make this available to all arches.
970 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300971#define TCGETS 0x5401
972
973static const char *tioctls[] = {
974 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
975 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
976 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
977 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
978 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
979 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
980 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
981 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
982 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
983 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
984 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
985 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
986 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
987 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
988 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
989};
990
991static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300992#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300993
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300994#define STRARRAY(arg, name, array) \
995 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
996 .arg_parm = { [arg] = &strarray__##array, }
997
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300998static struct syscall_fmt {
999 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001000 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001001 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001002 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001003 bool errmsg;
1004 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001005 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001006} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001007 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001008 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1009 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001010 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001011 { .name = "brk", .hexret = true,
1012 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001013 { .name = "chdir", .errmsg = true,
1014 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1015 { .name = "chmod", .errmsg = true,
1016 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1017 { .name = "chroot", .errmsg = true,
1018 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001019 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001020 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001021 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001022 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001023 { .name = "creat", .errmsg = true,
1024 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001025 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001026 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001028 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001029 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001030 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001031 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001032 { .name = "eventfd2", .errmsg = true,
1033 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001034 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001035 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1036 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001037 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001038 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001039 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001040 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001041 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001042 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001043 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001044 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001045 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001046 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1047 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001049 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001050 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001051 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1052 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001053 { .name = "fcntl", .errmsg = true,
1054 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1055 [1] = SCA_STRARRAY, /* cmd */ },
1056 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1057 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001058 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001059 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001060 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1061 [1] = SCA_FLOCK, /* cmd */ }, },
1062 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001063 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001064 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001065 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001066 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001067 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1068 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001069 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001070 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001071 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001072 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001073 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001074 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001075 { .name = "futex", .errmsg = true,
1076 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001077 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001078 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1079 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001080 { .name = "getdents", .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 = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001083 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001084 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1085 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001086 { .name = "getxattr", .errmsg = true,
1087 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1088 { .name = "inotify_add_watch", .errmsg = true,
1089 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001090 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001091 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001092#if defined(__i386__) || defined(__x86_64__)
1093/*
1094 * FIXME: Make this available to all arches.
1095 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001096 [1] = SCA_STRHEXARRAY, /* cmd */
1097 [2] = SCA_HEX, /* arg */ },
1098 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001099#else
1100 [2] = SCA_HEX, /* arg */ }, },
1101#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001102 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001103 { .name = "kill", .errmsg = true,
1104 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001105 { .name = "lchown", .errmsg = true,
1106 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1107 { .name = "lgetxattr", .errmsg = true,
1108 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001109 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001110 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001111 { .name = "listxattr", .errmsg = true,
1112 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001113 { .name = "llistxattr", .errmsg = true,
1114 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1115 { .name = "lremovexattr", .errmsg = true,
1116 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001117 { .name = "lseek", .errmsg = true,
1118 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1119 [2] = SCA_STRARRAY, /* whence */ },
1120 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001121 { .name = "lsetxattr", .errmsg = true,
1122 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001123 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1124 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001125 { .name = "lsxattr", .errmsg = true,
1126 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001127 { .name = "madvise", .errmsg = true,
1128 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1129 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001130 { .name = "mkdir", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001132 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001133 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1134 [1] = SCA_FILENAME, /* pathname */ }, },
1135 { .name = "mknod", .errmsg = true,
1136 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001137 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001138 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1139 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001140 { .name = "mlock", .errmsg = true,
1141 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1142 { .name = "mlockall", .errmsg = true,
1143 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001144 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001145 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001146 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001147 [3] = SCA_MMAP_FLAGS, /* flags */
1148 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001149 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001150 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1151 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001152 { .name = "mq_unlink", .errmsg = true,
1153 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001154 { .name = "mremap", .hexret = true,
1155 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001156 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001157 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001158 { .name = "munlock", .errmsg = true,
1159 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001160 { .name = "munmap", .errmsg = true,
1161 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001162 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001163 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001164 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001165 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1166 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001167 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001168 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1169 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001170 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001171 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1172 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001173 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001174 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001175 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001176 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001177 { .name = "perf_event_open", .errmsg = true,
1178 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1179 [2] = SCA_INT, /* cpu */
1180 [3] = SCA_FD, /* group_fd */
1181 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001182 { .name = "pipe2", .errmsg = true,
1183 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001184 { .name = "poll", .errmsg = true, .timeout = true, },
1185 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001186 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001187 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001188 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001189 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001190 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001191 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001192 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001193 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001194 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001195 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001196 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001197 { .name = "readlink", .errmsg = true,
1198 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001199 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001200 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1201 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001202 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001203 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001204 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001205 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1206 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001207 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001208 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1209 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001210 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001211 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1212 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001213 { .name = "removexattr", .errmsg = true,
1214 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001215 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001216 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001217 { .name = "rmdir", .errmsg = true,
1218 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001219 { .name = "rt_sigaction", .errmsg = true,
1220 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001221 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001222 { .name = "rt_sigqueueinfo", .errmsg = true,
1223 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1224 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1225 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001226 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001227 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001228 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1229 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001230 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001231 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1232 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001233 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001234 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1235 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001236 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1237 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001238 { .name = "setxattr", .errmsg = true,
1239 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001240 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001241 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001242 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001243 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1244 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001245 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001246 { .name = "socketpair", .errmsg = true,
1247 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1248 [1] = SCA_SK_TYPE, /* type */ },
1249 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001250 { .name = "stat", .errmsg = true, .alias = "newstat",
1251 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001252 { .name = "statfs", .errmsg = true,
1253 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1254 { .name = "swapoff", .errmsg = true,
1255 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1256 { .name = "swapon", .errmsg = true,
1257 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001258 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001259 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001260 { .name = "tgkill", .errmsg = true,
1261 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1262 { .name = "tkill", .errmsg = true,
1263 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001264 { .name = "truncate", .errmsg = true,
1265 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001266 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001267 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001268 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1269 [1] = SCA_FILENAME, /* pathname */ }, },
1270 { .name = "utime", .errmsg = true,
1271 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001272 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001273 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1274 [1] = SCA_FILENAME, /* filename */ }, },
1275 { .name = "utimes", .errmsg = true,
1276 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001277 { .name = "vmsplice", .errmsg = true,
1278 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001279 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001280 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001281 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001282 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001283};
1284
1285static int syscall_fmt__cmp(const void *name, const void *fmtp)
1286{
1287 const struct syscall_fmt *fmt = fmtp;
1288 return strcmp(name, fmt->name);
1289}
1290
1291static struct syscall_fmt *syscall_fmt__find(const char *name)
1292{
1293 const int nmemb = ARRAY_SIZE(syscall_fmts);
1294 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1295}
1296
1297struct syscall {
1298 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001299 int nr_args;
1300 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001301 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001302 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001303 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001304 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001305 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001306};
1307
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001308static size_t fprintf_duration(unsigned long t, FILE *fp)
1309{
1310 double duration = (double)t / NSEC_PER_MSEC;
1311 size_t printed = fprintf(fp, "(");
1312
1313 if (duration >= 1.0)
1314 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1315 else if (duration >= 0.01)
1316 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1317 else
1318 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001319 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001320}
1321
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001322/**
1323 * filename.ptr: The filename char pointer that will be vfs_getname'd
1324 * filename.entry_str_pos: Where to insert the string translated from
1325 * filename.ptr by the vfs_getname tracepoint/kprobe.
1326 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001327struct thread_trace {
1328 u64 entry_time;
1329 u64 exit_time;
1330 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001331 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001332 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001333 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001334 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001335 struct {
1336 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001337 short int entry_str_pos;
1338 bool pending_open;
1339 unsigned int namelen;
1340 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001341 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001342 struct {
1343 int max;
1344 char **table;
1345 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001346
1347 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001348};
1349
1350static struct thread_trace *thread_trace__new(void)
1351{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001352 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1353
1354 if (ttrace)
1355 ttrace->paths.max = -1;
1356
David Ahernbf2575c2013-10-08 21:26:53 -06001357 ttrace->syscall_stats = intlist__new(NULL);
1358
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001359 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001360}
1361
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001362static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001363{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001364 struct thread_trace *ttrace;
1365
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001366 if (thread == NULL)
1367 goto fail;
1368
Namhyung Kim89dceb22014-10-06 09:46:03 +09001369 if (thread__priv(thread) == NULL)
1370 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001371
Namhyung Kim89dceb22014-10-06 09:46:03 +09001372 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001373 goto fail;
1374
Namhyung Kim89dceb22014-10-06 09:46:03 +09001375 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001376 ++ttrace->nr_events;
1377
1378 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001379fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001380 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001381 "WARNING: not enough memory, dropping samples!\n");
1382 return NULL;
1383}
1384
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001385#define TRACE_PFMAJ (1 << 0)
1386#define TRACE_PFMIN (1 << 1)
1387
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001388static const size_t trace__entry_str_size = 2048;
1389
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001390struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001391 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001392 struct {
1393 int machine;
1394 int open_id;
1395 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001396 struct {
1397 int max;
1398 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001399 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001400 struct perf_evsel *sys_enter,
1401 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001402 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001403 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001404 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001405 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001406 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001407 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001408 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001409 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001410 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001411 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001412 struct {
1413 size_t nr;
1414 int *entries;
1415 } ev_qualifier_ids;
David Ahernbdc89662013-08-28 22:29:53 -06001416 struct intlist *tid_list;
1417 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001418 struct {
1419 size_t nr;
1420 pid_t *entries;
1421 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001422 double duration_filter;
1423 double runtime_ms;
1424 struct {
1425 u64 vfs_getname,
1426 proc_getname;
1427 } stats;
1428 bool not_ev_qualifier;
1429 bool live;
1430 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001431 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001432 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001433 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001434 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001435 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001436 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001437 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001438 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001439 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001440 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001441};
1442
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001443static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001444{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001445 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001446
1447 if (fd > ttrace->paths.max) {
1448 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1449
1450 if (npath == NULL)
1451 return -1;
1452
1453 if (ttrace->paths.max != -1) {
1454 memset(npath + ttrace->paths.max + 1, 0,
1455 (fd - ttrace->paths.max) * sizeof(char *));
1456 } else {
1457 memset(npath, 0, (fd + 1) * sizeof(char *));
1458 }
1459
1460 ttrace->paths.table = npath;
1461 ttrace->paths.max = fd;
1462 }
1463
1464 ttrace->paths.table[fd] = strdup(pathname);
1465
1466 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1467}
1468
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001469static int thread__read_fd_path(struct thread *thread, int fd)
1470{
1471 char linkname[PATH_MAX], pathname[PATH_MAX];
1472 struct stat st;
1473 int ret;
1474
1475 if (thread->pid_ == thread->tid) {
1476 scnprintf(linkname, sizeof(linkname),
1477 "/proc/%d/fd/%d", thread->pid_, fd);
1478 } else {
1479 scnprintf(linkname, sizeof(linkname),
1480 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1481 }
1482
1483 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1484 return -1;
1485
1486 ret = readlink(linkname, pathname, sizeof(pathname));
1487
1488 if (ret < 0 || ret > st.st_size)
1489 return -1;
1490
1491 pathname[ret] = '\0';
1492 return trace__set_fd_pathname(thread, fd, pathname);
1493}
1494
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001495static const char *thread__fd_path(struct thread *thread, int fd,
1496 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001497{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001498 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001499
1500 if (ttrace == NULL)
1501 return NULL;
1502
1503 if (fd < 0)
1504 return NULL;
1505
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001506 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001507 if (!trace->live)
1508 return NULL;
1509 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001510 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001511 return NULL;
1512 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001513
1514 return ttrace->paths.table[fd];
1515}
1516
1517static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1518 struct syscall_arg *arg)
1519{
1520 int fd = arg->val;
1521 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001522 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001523
1524 if (path)
1525 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1526
1527 return printed;
1528}
1529
1530static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1531 struct syscall_arg *arg)
1532{
1533 int fd = arg->val;
1534 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001535 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001536
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001537 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1538 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001539
1540 return printed;
1541}
1542
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001543static void thread__set_filename_pos(struct thread *thread, const char *bf,
1544 unsigned long ptr)
1545{
1546 struct thread_trace *ttrace = thread__priv(thread);
1547
1548 ttrace->filename.ptr = ptr;
1549 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1550}
1551
1552static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1553 struct syscall_arg *arg)
1554{
1555 unsigned long ptr = arg->val;
1556
1557 if (!arg->trace->vfs_getname)
1558 return scnprintf(bf, size, "%#x", ptr);
1559
1560 thread__set_filename_pos(arg->thread, bf, ptr);
1561 return 0;
1562}
1563
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001564static bool trace__filter_duration(struct trace *trace, double t)
1565{
1566 return t < (trace->duration_filter * NSEC_PER_MSEC);
1567}
1568
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001569static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1570{
1571 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1572
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001573 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001574}
1575
Namhyung Kimf15eb532012-10-05 14:02:16 +09001576static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001577static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001578
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001579static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001580{
1581 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001582 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001583}
1584
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001585static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001586 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001587{
1588 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001589 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001590
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001591 if (trace->multiple_threads) {
1592 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001593 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001594 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001595 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001596
1597 return printed;
1598}
1599
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001600static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001601 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001602{
1603 int ret = 0;
1604
1605 switch (event->header.type) {
1606 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001607 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001608 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001609 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001610 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001611 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001612 break;
1613 }
1614
1615 return ret;
1616}
1617
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001618static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001619 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001620 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001621 struct machine *machine)
1622{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001623 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001624 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001625}
1626
1627static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1628{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001629 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001630
1631 if (err)
1632 return err;
1633
David Ahern8fb598e2013-09-28 13:13:00 -06001634 trace->host = machine__new_host();
1635 if (trace->host == NULL)
1636 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001637
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001638 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001639 return -errno;
1640
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001641 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001642 evlist->threads, trace__tool_process, false,
1643 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001644 if (err)
1645 symbol__exit();
1646
1647 return err;
1648}
1649
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001650static int syscall__set_arg_fmts(struct syscall *sc)
1651{
1652 struct format_field *field;
1653 int idx = 0;
1654
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001655 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001656 if (sc->arg_scnprintf == NULL)
1657 return -1;
1658
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001659 if (sc->fmt)
1660 sc->arg_parm = sc->fmt->arg_parm;
1661
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001662 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001663 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1664 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1665 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001666 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1667 ++idx;
1668 }
1669
1670 return 0;
1671}
1672
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001673static int trace__read_syscall_info(struct trace *trace, int id)
1674{
1675 char tp_name[128];
1676 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001677 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001678
1679 if (name == NULL)
1680 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001681
1682 if (id > trace->syscalls.max) {
1683 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1684
1685 if (nsyscalls == NULL)
1686 return -1;
1687
1688 if (trace->syscalls.max != -1) {
1689 memset(nsyscalls + trace->syscalls.max + 1, 0,
1690 (id - trace->syscalls.max) * sizeof(*sc));
1691 } else {
1692 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1693 }
1694
1695 trace->syscalls.table = nsyscalls;
1696 trace->syscalls.max = id;
1697 }
1698
1699 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001700 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001701
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001702 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001703
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001704 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001705 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001706
1707 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1708 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001709 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001710 }
1711
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001712 if (sc->tp_format == NULL)
1713 return -1;
1714
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001715 sc->args = sc->tp_format->format.fields;
1716 sc->nr_args = sc->tp_format->format.nr_fields;
1717 /* drop nr field - not relevant here; does not exist on older kernels */
1718 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1719 sc->args = sc->args->next;
1720 --sc->nr_args;
1721 }
1722
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001723 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1724
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001725 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001726}
1727
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001728static int trace__validate_ev_qualifier(struct trace *trace)
1729{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001730 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001731 struct str_node *pos;
1732
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001733 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1734 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1735 sizeof(trace->ev_qualifier_ids.entries[0]));
1736
1737 if (trace->ev_qualifier_ids.entries == NULL) {
1738 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1739 trace->output);
1740 err = -EINVAL;
1741 goto out;
1742 }
1743
1744 i = 0;
1745
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001746 strlist__for_each(pos, trace->ev_qualifier) {
1747 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001748 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001749
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001750 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001751 if (err == 0) {
1752 fputs("Error:\tInvalid syscall ", trace->output);
1753 err = -EINVAL;
1754 } else {
1755 fputs(", ", trace->output);
1756 }
1757
1758 fputs(sc, trace->output);
1759 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001760
1761 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001762 }
1763
1764 if (err < 0) {
1765 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1766 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001767 zfree(&trace->ev_qualifier_ids.entries);
1768 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001769 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001770out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001771 return err;
1772}
1773
David Ahern55d43bca2015-02-19 15:00:22 -05001774/*
1775 * args is to be interpreted as a series of longs but we need to handle
1776 * 8-byte unaligned accesses. args points to raw_data within the event
1777 * and raw_data is guaranteed to be 8-byte unaligned because it is
1778 * preceded by raw_size which is a u32. So we need to copy args to a temp
1779 * variable to read it. Most notably this avoids extended load instructions
1780 * on unaligned addresses
1781 */
1782
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001783static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001784 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001785 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001786{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001787 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001788 unsigned char *p;
1789 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001790
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001791 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001792 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001793 u8 bit = 1;
1794 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001795 .idx = 0,
1796 .mask = 0,
1797 .trace = trace,
1798 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001799 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001800
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001801 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001802 field = field->next, ++arg.idx, bit <<= 1) {
1803 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001804 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001805
1806 /* special care for unaligned accesses */
1807 p = args + sizeof(unsigned long) * arg.idx;
1808 memcpy(&val, p, sizeof(val));
1809
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001810 /*
1811 * Suppress this argument if its value is zero and
1812 * and we don't have a string associated in an
1813 * strarray for it.
1814 */
David Ahern55d43bca2015-02-19 15:00:22 -05001815 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001816 !(sc->arg_scnprintf &&
1817 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1818 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001819 continue;
1820
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001821 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001822 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001823 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001824 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001825 if (sc->arg_parm)
1826 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001827 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1828 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001829 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001830 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001831 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001832 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001833 }
1834 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001835 int i = 0;
1836
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001837 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001838 /* special care for unaligned accesses */
1839 p = args + sizeof(unsigned long) * i;
1840 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001841 printed += scnprintf(bf + printed, size - printed,
1842 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001843 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001844 ++i;
1845 }
1846 }
1847
1848 return printed;
1849}
1850
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001851typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001852 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001853 struct perf_sample *sample);
1854
1855static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001856 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001857{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001858
1859 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001860
1861 /*
1862 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1863 * before that, leaving at a higher verbosity level till that is
1864 * explained. Reproduced with plain ftrace with:
1865 *
1866 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1867 * grep "NR -1 " /t/trace_pipe
1868 *
1869 * After generating some load on the machine.
1870 */
1871 if (verbose > 1) {
1872 static u64 n;
1873 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1874 id, perf_evsel__name(evsel), ++n);
1875 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001876 return NULL;
1877 }
1878
1879 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1880 trace__read_syscall_info(trace, id))
1881 goto out_cant_read;
1882
1883 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1884 goto out_cant_read;
1885
1886 return &trace->syscalls.table[id];
1887
1888out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001889 if (verbose) {
1890 fprintf(trace->output, "Problems reading syscall %d", id);
1891 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1892 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1893 fputs(" information\n", trace->output);
1894 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001895 return NULL;
1896}
1897
David Ahernbf2575c2013-10-08 21:26:53 -06001898static void thread__update_stats(struct thread_trace *ttrace,
1899 int id, struct perf_sample *sample)
1900{
1901 struct int_node *inode;
1902 struct stats *stats;
1903 u64 duration = 0;
1904
1905 inode = intlist__findnew(ttrace->syscall_stats, id);
1906 if (inode == NULL)
1907 return;
1908
1909 stats = inode->priv;
1910 if (stats == NULL) {
1911 stats = malloc(sizeof(struct stats));
1912 if (stats == NULL)
1913 return;
1914 init_stats(stats);
1915 inode->priv = stats;
1916 }
1917
1918 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1919 duration = sample->time - ttrace->entry_time;
1920
1921 update_stats(stats, duration);
1922}
1923
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001924static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1925{
1926 struct thread_trace *ttrace;
1927 u64 duration;
1928 size_t printed;
1929
1930 if (trace->current == NULL)
1931 return 0;
1932
1933 ttrace = thread__priv(trace->current);
1934
1935 if (!ttrace->entry_pending)
1936 return 0;
1937
1938 duration = sample->time - ttrace->entry_time;
1939
1940 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1941 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1942 ttrace->entry_pending = false;
1943
1944 return printed;
1945}
1946
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001947static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001948 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001949 struct perf_sample *sample)
1950{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001951 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001952 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001953 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001954 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001955 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001956 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001957 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001958
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001959 if (sc == NULL)
1960 return -1;
1961
David Ahern8fb598e2013-09-28 13:13:00 -06001962 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001963 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001964 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001965 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001966
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001967 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001968
1969 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001970 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001971 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001972 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001973 }
1974
David Ahern13f22a22015-03-19 12:23:03 -06001975 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001976 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001977
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001978 ttrace->entry_time = sample->time;
1979 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001980 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001981
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001982 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001983 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001984
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001985 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001986 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001987 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1988 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001989 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001990 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001991 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001992 /* See trace__vfs_getname & trace__sys_exit */
1993 ttrace->filename.pending_open = false;
1994 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001995
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001996 if (trace->current != thread) {
1997 thread__put(trace->current);
1998 trace->current = thread__get(thread);
1999 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002000 err = 0;
2001out_put:
2002 thread__put(thread);
2003 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002004}
2005
2006static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002007 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002008 struct perf_sample *sample)
2009{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002010 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002011 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002012 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002013 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002014 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002015 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002016
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002017 if (sc == NULL)
2018 return -1;
2019
David Ahern8fb598e2013-09-28 13:13:00 -06002020 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002021 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002022 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002023 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002024
David Ahernbf2575c2013-10-08 21:26:53 -06002025 if (trace->summary)
2026 thread__update_stats(ttrace, id, sample);
2027
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002028 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002029
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002030 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2031 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2032 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002033 ++trace->stats.vfs_getname;
2034 }
2035
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002036 ttrace->exit_time = sample->time;
2037
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002038 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002039 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002040 if (trace__filter_duration(trace, duration))
2041 goto out;
2042 } else if (trace->duration_filter)
2043 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002044
David Ahernfd2eaba2013-11-12 09:31:15 -07002045 if (trace->summary_only)
2046 goto out;
2047
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002048 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002049
2050 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002051 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002052 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002053 fprintf(trace->output, " ... [");
2054 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2055 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002056 }
2057
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002058 if (sc->fmt == NULL) {
2059signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002060 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002061 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002062 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002063 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2064 *e = audit_errno_to_name(-ret);
2065
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002066 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002067 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002068 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002069 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002070 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002071 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002072 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002073
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002074 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002075out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002076 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002077 err = 0;
2078out_put:
2079 thread__put(thread);
2080 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002081}
2082
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002083static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002084 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002085 struct perf_sample *sample)
2086{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002087 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2088 struct thread_trace *ttrace;
2089 size_t filename_len, entry_str_len, to_move;
2090 ssize_t remaining_space;
2091 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002092 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002093
2094 if (!thread)
2095 goto out;
2096
2097 ttrace = thread__priv(thread);
2098 if (!ttrace)
2099 goto out;
2100
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002101 filename_len = strlen(filename);
2102
2103 if (ttrace->filename.namelen < filename_len) {
2104 char *f = realloc(ttrace->filename.name, filename_len + 1);
2105
2106 if (f == NULL)
2107 goto out;
2108
2109 ttrace->filename.namelen = filename_len;
2110 ttrace->filename.name = f;
2111 }
2112
2113 strcpy(ttrace->filename.name, filename);
2114 ttrace->filename.pending_open = true;
2115
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002116 if (!ttrace->filename.ptr)
2117 goto out;
2118
2119 entry_str_len = strlen(ttrace->entry_str);
2120 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2121 if (remaining_space <= 0)
2122 goto out;
2123
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002124 if (filename_len > (size_t)remaining_space) {
2125 filename += filename_len - remaining_space;
2126 filename_len = remaining_space;
2127 }
2128
2129 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2130 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2131 memmove(pos + filename_len, pos, to_move);
2132 memcpy(pos, filename, filename_len);
2133
2134 ttrace->filename.ptr = 0;
2135 ttrace->filename.entry_str_pos = 0;
2136out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002137 return 0;
2138}
2139
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002140static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002141 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002142 struct perf_sample *sample)
2143{
2144 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2145 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002146 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002147 sample->pid,
2148 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002149 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002150
2151 if (ttrace == NULL)
2152 goto out_dump;
2153
2154 ttrace->runtime_ms += runtime_ms;
2155 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002156 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002157 return 0;
2158
2159out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002160 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002161 evsel->name,
2162 perf_evsel__strval(evsel, sample, "comm"),
2163 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2164 runtime,
2165 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002166 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002167 return 0;
2168}
2169
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002170static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2171 union perf_event *event __maybe_unused,
2172 struct perf_sample *sample)
2173{
2174 trace__printf_interrupted_entry(trace, sample);
2175 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002176
2177 if (trace->trace_syscalls)
2178 fprintf(trace->output, "( ): ");
2179
2180 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002181
2182 if (evsel->tp_format) {
2183 event_format__fprintf(evsel->tp_format, sample->cpu,
2184 sample->raw_data, sample->raw_size,
2185 trace->output);
2186 }
2187
2188 fprintf(trace->output, ")\n");
2189 return 0;
2190}
2191
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002192static void print_location(FILE *f, struct perf_sample *sample,
2193 struct addr_location *al,
2194 bool print_dso, bool print_sym)
2195{
2196
2197 if ((verbose || print_dso) && al->map)
2198 fprintf(f, "%s@", al->map->dso->long_name);
2199
2200 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002201 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002202 al->addr - al->sym->start);
2203 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002204 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002205 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002206 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002207}
2208
2209static int trace__pgfault(struct trace *trace,
2210 struct perf_evsel *evsel,
2211 union perf_event *event,
2212 struct perf_sample *sample)
2213{
2214 struct thread *thread;
2215 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2216 struct addr_location al;
2217 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002218 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002219 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002220
2221 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002222 ttrace = thread__trace(thread, trace->output);
2223 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002224 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002225
2226 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2227 ttrace->pfmaj++;
2228 else
2229 ttrace->pfmin++;
2230
2231 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002232 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002233
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002234 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002235 sample->ip, &al);
2236
2237 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2238
2239 fprintf(trace->output, "%sfault [",
2240 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2241 "maj" : "min");
2242
2243 print_location(trace->output, sample, &al, false, true);
2244
2245 fprintf(trace->output, "] => ");
2246
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002247 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002248 sample->addr, &al);
2249
2250 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002251 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002252 MAP__FUNCTION, sample->addr, &al);
2253
2254 if (al.map)
2255 map_type = 'x';
2256 else
2257 map_type = '?';
2258 }
2259
2260 print_location(trace->output, sample, &al, true, false);
2261
2262 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002263out:
2264 err = 0;
2265out_put:
2266 thread__put(thread);
2267 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002268}
2269
David Ahernbdc89662013-08-28 22:29:53 -06002270static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2271{
2272 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2273 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2274 return false;
2275
2276 if (trace->pid_list || trace->tid_list)
2277 return true;
2278
2279 return false;
2280}
2281
David Ahern6810fc92013-08-28 22:29:52 -06002282static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002283 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002284 struct perf_sample *sample,
2285 struct perf_evsel *evsel,
2286 struct machine *machine __maybe_unused)
2287{
2288 struct trace *trace = container_of(tool, struct trace, tool);
2289 int err = 0;
2290
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002291 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002292
David Ahernbdc89662013-08-28 22:29:53 -06002293 if (skip_sample(trace, sample))
2294 return 0;
2295
David Ahern4bb09192013-09-04 12:37:43 -06002296 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002297 trace->base_time = sample->time;
2298
David Ahern31605652013-12-04 19:41:41 -07002299 if (handler) {
2300 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002301 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002302 }
David Ahern6810fc92013-08-28 22:29:52 -06002303
2304 return err;
2305}
2306
David Ahernbdc89662013-08-28 22:29:53 -06002307static int parse_target_str(struct trace *trace)
2308{
2309 if (trace->opts.target.pid) {
2310 trace->pid_list = intlist__new(trace->opts.target.pid);
2311 if (trace->pid_list == NULL) {
2312 pr_err("Error parsing process id string\n");
2313 return -EINVAL;
2314 }
2315 }
2316
2317 if (trace->opts.target.tid) {
2318 trace->tid_list = intlist__new(trace->opts.target.tid);
2319 if (trace->tid_list == NULL) {
2320 pr_err("Error parsing thread id string\n");
2321 return -EINVAL;
2322 }
2323 }
2324
2325 return 0;
2326}
2327
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002328static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002329{
2330 unsigned int rec_argc, i, j;
2331 const char **rec_argv;
2332 const char * const record_args[] = {
2333 "record",
2334 "-R",
2335 "-m", "1024",
2336 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002337 };
2338
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002339 const char * const sc_args[] = { "-e", };
2340 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2341 const char * const majpf_args[] = { "-e", "major-faults" };
2342 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2343 const char * const minpf_args[] = { "-e", "minor-faults" };
2344 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2345
David Ahern9aca7f12013-12-04 19:41:39 -07002346 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002347 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2348 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002349 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2350
2351 if (rec_argv == NULL)
2352 return -ENOMEM;
2353
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002354 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002355 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002356 rec_argv[j++] = record_args[i];
2357
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002358 if (trace->trace_syscalls) {
2359 for (i = 0; i < sc_args_nr; i++)
2360 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002361
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002362 /* event string may be different for older kernels - e.g., RHEL6 */
2363 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2364 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2365 else if (is_valid_tracepoint("syscalls:sys_enter"))
2366 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2367 else {
2368 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2369 return -1;
2370 }
David Ahern9aca7f12013-12-04 19:41:39 -07002371 }
David Ahern9aca7f12013-12-04 19:41:39 -07002372
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002373 if (trace->trace_pgfaults & TRACE_PFMAJ)
2374 for (i = 0; i < majpf_args_nr; i++)
2375 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002376
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002377 if (trace->trace_pgfaults & TRACE_PFMIN)
2378 for (i = 0; i < minpf_args_nr; i++)
2379 rec_argv[j++] = minpf_args[i];
2380
2381 for (i = 0; i < (unsigned int)argc; i++)
2382 rec_argv[j++] = argv[i];
2383
2384 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002385}
2386
David Ahernbf2575c2013-10-08 21:26:53 -06002387static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2388
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002389static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002390{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002391 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002392 if (evsel == NULL)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002393 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002394
2395 if (perf_evsel__field(evsel, "pathname") == NULL) {
2396 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002397 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002398 }
2399
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002400 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002401 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002402 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002403}
2404
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002405static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2406 u64 config)
2407{
2408 struct perf_evsel *evsel;
2409 struct perf_event_attr attr = {
2410 .type = PERF_TYPE_SOFTWARE,
2411 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002412 };
2413
2414 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002415 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002416
2417 event_attr_init(&attr);
2418
2419 evsel = perf_evsel__new(&attr);
2420 if (!evsel)
2421 return -ENOMEM;
2422
2423 evsel->handler = trace__pgfault;
2424 perf_evlist__add(evlist, evsel);
2425
2426 return 0;
2427}
2428
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002429static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2430{
2431 const u32 type = event->header.type;
2432 struct perf_evsel *evsel;
2433
2434 if (!trace->full_time && trace->base_time == 0)
2435 trace->base_time = sample->time;
2436
2437 if (type != PERF_RECORD_SAMPLE) {
2438 trace__process_event(trace, trace->host, event, sample);
2439 return;
2440 }
2441
2442 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2443 if (evsel == NULL) {
2444 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2445 return;
2446 }
2447
2448 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2449 sample->raw_data == NULL) {
2450 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2451 perf_evsel__name(evsel), sample->tid,
2452 sample->cpu, sample->raw_size);
2453 } else {
2454 tracepoint_handler handler = evsel->handler;
2455 handler(trace, evsel, event, sample);
2456 }
2457}
2458
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002459static int trace__add_syscall_newtp(struct trace *trace)
2460{
2461 int ret = -1;
2462 struct perf_evlist *evlist = trace->evlist;
2463 struct perf_evsel *sys_enter, *sys_exit;
2464
2465 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2466 if (sys_enter == NULL)
2467 goto out;
2468
2469 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2470 goto out_delete_sys_enter;
2471
2472 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2473 if (sys_exit == NULL)
2474 goto out_delete_sys_enter;
2475
2476 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2477 goto out_delete_sys_exit;
2478
2479 perf_evlist__add(evlist, sys_enter);
2480 perf_evlist__add(evlist, sys_exit);
2481
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002482 trace->syscalls.events.sys_enter = sys_enter;
2483 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002484
2485 ret = 0;
2486out:
2487 return ret;
2488
2489out_delete_sys_exit:
2490 perf_evsel__delete_priv(sys_exit);
2491out_delete_sys_enter:
2492 perf_evsel__delete_priv(sys_enter);
2493 goto out;
2494}
2495
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002496static int trace__set_ev_qualifier_filter(struct trace *trace)
2497{
2498 int err = -1;
2499 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2500 trace->ev_qualifier_ids.nr,
2501 trace->ev_qualifier_ids.entries);
2502
2503 if (filter == NULL)
2504 goto out_enomem;
2505
2506 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2507 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2508
2509 free(filter);
2510out:
2511 return err;
2512out_enomem:
2513 errno = ENOMEM;
2514 goto out;
2515}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002516
Namhyung Kimf15eb532012-10-05 14:02:16 +09002517static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002518{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002519 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002520 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002521 int err = -1, i;
2522 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002523 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002524 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002525
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002526 trace->live = true;
2527
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002528 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002529 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002530
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002531 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002532 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002533
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002534 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002535 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002536 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002537 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002538
2539 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2540 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002541 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002542
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002543 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002544 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2545 trace__sched_stat_runtime))
2546 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002547
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002548 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2549 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002550 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002551 goto out_delete_evlist;
2552 }
2553
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002554 err = trace__symbols_init(trace, evlist);
2555 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002556 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002557 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002558 }
2559
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002560 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002561
Namhyung Kimf15eb532012-10-05 14:02:16 +09002562 signal(SIGCHLD, sig_handler);
2563 signal(SIGINT, sig_handler);
2564
2565 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002566 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002567 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002568 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002569 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002570 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002571 }
2572 }
2573
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002574 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002575 if (err < 0)
2576 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002577
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002578 /*
2579 * Better not use !target__has_task() here because we need to cover the
2580 * case where no threads were specified in the command line, but a
2581 * workload was, and in that case we will fill in the thread_map when
2582 * we fork the workload in perf_evlist__prepare_workload.
2583 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002584 if (trace->filter_pids.nr > 0)
2585 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002586 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002587 err = perf_evlist__set_filter_pid(evlist, getpid());
2588
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002589 if (err < 0)
2590 goto out_error_mem;
2591
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002592 if (trace->ev_qualifier_ids.nr > 0) {
2593 err = trace__set_ev_qualifier_filter(trace);
2594 if (err < 0)
2595 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002596
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002597 pr_debug("event qualifier tracepoint filter: %s\n",
2598 trace->syscalls.events.sys_exit->filter);
2599 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002600
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002601 err = perf_evlist__apply_filters(evlist, &evsel);
2602 if (err < 0)
2603 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002604
Jiri Olsaf8850372013-11-28 17:57:22 +01002605 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002606 if (err < 0)
2607 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002608
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002609 if (!target__none(&trace->opts.target))
2610 perf_evlist__enable(evlist);
2611
Namhyung Kimf15eb532012-10-05 14:02:16 +09002612 if (forks)
2613 perf_evlist__start_workload(evlist);
2614
Jiri Olsae13798c2015-06-23 00:36:02 +02002615 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002616 evlist->threads->nr > 1 ||
2617 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002618again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002619 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002620
2621 for (i = 0; i < evlist->nr_mmaps; i++) {
2622 union perf_event *event;
2623
2624 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002625 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002626
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002627 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002628
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002629 err = perf_evlist__parse_sample(evlist, event, &sample);
2630 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002631 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002632 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002633 }
2634
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002635 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002636next_event:
2637 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002638
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002639 if (interrupted)
2640 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002641
2642 if (done && !draining) {
2643 perf_evlist__disable(evlist);
2644 draining = true;
2645 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002646 }
2647 }
2648
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002649 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002650 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002651
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002652 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2653 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2654 draining = true;
2655
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002656 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002657 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002658 } else {
2659 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002660 }
2661
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002662out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002663 thread__zput(trace->current);
2664
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002665 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002666
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002667 if (!err) {
2668 if (trace->summary)
2669 trace__fprintf_thread_summary(trace, trace->output);
2670
2671 if (trace->show_tool_stats) {
2672 fprintf(trace->output, "Stats:\n "
2673 " vfs_getname : %" PRIu64 "\n"
2674 " proc_getname: %" PRIu64 "\n",
2675 trace->stats.vfs_getname,
2676 trace->stats.proc_getname);
2677 }
2678 }
David Ahernbf2575c2013-10-08 21:26:53 -06002679
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002680out_delete_evlist:
2681 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002682 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002683 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002684 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002685{
2686 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002687
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002688out_error_sched_stat_runtime:
2689 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2690 goto out_error;
2691
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002692out_error_raw_syscalls:
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002693 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002694 goto out_error;
2695
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002696out_error_mmap:
2697 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2698 goto out_error;
2699
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002700out_error_open:
2701 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2702
2703out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002704 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302705 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002706
2707out_error_apply_filters:
2708 fprintf(trace->output,
2709 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2710 evsel->filter, perf_evsel__name(evsel), errno,
2711 strerror_r(errno, errbuf, sizeof(errbuf)));
2712 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002713}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002714out_error_mem:
2715 fprintf(trace->output, "Not enough memory to run!\n");
2716 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002717
2718out_errno:
2719 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2720 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002721}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002722
David Ahern6810fc92013-08-28 22:29:52 -06002723static int trace__replay(struct trace *trace)
2724{
2725 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002726 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002727 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002728 struct perf_data_file file = {
2729 .path = input_name,
2730 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002731 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002732 };
David Ahern6810fc92013-08-28 22:29:52 -06002733 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002734 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002735 int err = -1;
2736
2737 trace->tool.sample = trace__process_sample;
2738 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002739 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002740 trace->tool.comm = perf_event__process_comm;
2741 trace->tool.exit = perf_event__process_exit;
2742 trace->tool.fork = perf_event__process_fork;
2743 trace->tool.attr = perf_event__process_attr;
2744 trace->tool.tracing_data = perf_event__process_tracing_data;
2745 trace->tool.build_id = perf_event__process_build_id;
2746
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002747 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002748 trace->tool.ordering_requires_timestamps = true;
2749
2750 /* add tid to output */
2751 trace->multiple_threads = true;
2752
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002753 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002754 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002755 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002756
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002757 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002758 goto out;
2759
David Ahern8fb598e2013-09-28 13:13:00 -06002760 trace->host = &session->machines.host;
2761
David Ahern6810fc92013-08-28 22:29:52 -06002762 err = perf_session__set_tracepoints_handlers(session, handlers);
2763 if (err)
2764 goto out;
2765
Namhyung Kim003824e2013-11-12 15:25:00 +09002766 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2767 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002768 /* older kernels have syscalls tp versus raw_syscalls */
2769 if (evsel == NULL)
2770 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2771 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002772
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002773 if (evsel &&
2774 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2775 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002776 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2777 goto out;
2778 }
2779
2780 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2781 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002782 if (evsel == NULL)
2783 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2784 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002785 if (evsel &&
2786 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2787 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002788 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002789 goto out;
2790 }
2791
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002792 evlist__for_each(session->evlist, evsel) {
2793 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2794 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2795 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2796 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2797 evsel->handler = trace__pgfault;
2798 }
2799
David Ahernbdc89662013-08-28 22:29:53 -06002800 err = parse_target_str(trace);
2801 if (err != 0)
2802 goto out;
2803
David Ahern6810fc92013-08-28 22:29:52 -06002804 setup_pager();
2805
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002806 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002807 if (err)
2808 pr_err("Failed to process events, error %d", err);
2809
David Ahernbf2575c2013-10-08 21:26:53 -06002810 else if (trace->summary)
2811 trace__fprintf_thread_summary(trace, trace->output);
2812
David Ahern6810fc92013-08-28 22:29:52 -06002813out:
2814 perf_session__delete(session);
2815
2816 return err;
2817}
2818
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002819static size_t trace__fprintf_threads_header(FILE *fp)
2820{
2821 size_t printed;
2822
Pekka Enberg99ff7152013-11-12 16:42:14 +02002823 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002824
2825 return printed;
2826}
2827
2828static size_t thread__dump_stats(struct thread_trace *ttrace,
2829 struct trace *trace, FILE *fp)
2830{
2831 struct stats *stats;
2832 size_t printed = 0;
2833 struct syscall *sc;
2834 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2835
2836 if (inode == NULL)
2837 return 0;
2838
2839 printed += fprintf(fp, "\n");
2840
Milian Wolff834fd462015-08-06 11:24:29 +02002841 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2842 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2843 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002844
David Ahernbf2575c2013-10-08 21:26:53 -06002845 /* each int_node is a syscall */
2846 while (inode) {
2847 stats = inode->priv;
2848 if (stats) {
2849 double min = (double)(stats->min) / NSEC_PER_MSEC;
2850 double max = (double)(stats->max) / NSEC_PER_MSEC;
2851 double avg = avg_stats(stats);
2852 double pct;
2853 u64 n = (u64) stats->n;
2854
2855 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2856 avg /= NSEC_PER_MSEC;
2857
2858 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002859 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002860 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2861 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002862 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002863 }
2864
2865 inode = intlist__next(inode);
2866 }
2867
2868 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002869
2870 return printed;
2871}
2872
David Ahern896cbb52013-09-28 13:12:59 -06002873/* struct used to pass data to per-thread function */
2874struct summary_data {
2875 FILE *fp;
2876 struct trace *trace;
2877 size_t printed;
2878};
2879
2880static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2881{
2882 struct summary_data *data = priv;
2883 FILE *fp = data->fp;
2884 size_t printed = data->printed;
2885 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002886 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002887 double ratio;
2888
2889 if (ttrace == NULL)
2890 return 0;
2891
2892 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2893
Pekka Enberg15e65c62013-11-14 18:43:30 +02002894 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002895 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002896 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002897 if (ttrace->pfmaj)
2898 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2899 if (ttrace->pfmin)
2900 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002901 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002902 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002903
2904 data->printed += printed;
2905
2906 return 0;
2907}
2908
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002909static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2910{
David Ahern896cbb52013-09-28 13:12:59 -06002911 struct summary_data data = {
2912 .fp = fp,
2913 .trace = trace
2914 };
2915 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002916
David Ahern896cbb52013-09-28 13:12:59 -06002917 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002918
David Ahern896cbb52013-09-28 13:12:59 -06002919 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002920}
2921
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002922static int trace__set_duration(const struct option *opt, const char *str,
2923 int unset __maybe_unused)
2924{
2925 struct trace *trace = opt->value;
2926
2927 trace->duration_filter = atof(str);
2928 return 0;
2929}
2930
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002931static int trace__set_filter_pids(const struct option *opt, const char *str,
2932 int unset __maybe_unused)
2933{
2934 int ret = -1;
2935 size_t i;
2936 struct trace *trace = opt->value;
2937 /*
2938 * FIXME: introduce a intarray class, plain parse csv and create a
2939 * { int nr, int entries[] } struct...
2940 */
2941 struct intlist *list = intlist__new(str);
2942
2943 if (list == NULL)
2944 return -1;
2945
2946 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2947 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2948
2949 if (trace->filter_pids.entries == NULL)
2950 goto out;
2951
2952 trace->filter_pids.entries[0] = getpid();
2953
2954 for (i = 1; i < trace->filter_pids.nr; ++i)
2955 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2956
2957 intlist__delete(list);
2958 ret = 0;
2959out:
2960 return ret;
2961}
2962
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002963static int trace__open_output(struct trace *trace, const char *filename)
2964{
2965 struct stat st;
2966
2967 if (!stat(filename, &st) && st.st_size) {
2968 char oldname[PATH_MAX];
2969
2970 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2971 unlink(oldname);
2972 rename(filename, oldname);
2973 }
2974
2975 trace->output = fopen(filename, "w");
2976
2977 return trace->output == NULL ? -errno : 0;
2978}
2979
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002980static int parse_pagefaults(const struct option *opt, const char *str,
2981 int unset __maybe_unused)
2982{
2983 int *trace_pgfaults = opt->value;
2984
2985 if (strcmp(str, "all") == 0)
2986 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2987 else if (strcmp(str, "maj") == 0)
2988 *trace_pgfaults |= TRACE_PFMAJ;
2989 else if (strcmp(str, "min") == 0)
2990 *trace_pgfaults |= TRACE_PFMIN;
2991 else
2992 return -1;
2993
2994 return 0;
2995}
2996
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002997static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2998{
2999 struct perf_evsel *evsel;
3000
3001 evlist__for_each(evlist, evsel)
3002 evsel->handler = handler;
3003}
3004
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003005int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3006{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003007 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003008 "perf trace [<options>] [<command>]",
3009 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003010 "perf trace record [<options>] [<command>]",
3011 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003012 NULL
3013 };
3014 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003015 .audit = {
3016 .machine = audit_detect_machine(),
3017 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3018 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003019 .syscalls = {
3020 . max = -1,
3021 },
3022 .opts = {
3023 .target = {
3024 .uid = UINT_MAX,
3025 .uses_mmap = true,
3026 },
3027 .user_freq = UINT_MAX,
3028 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003029 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003030 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003031 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003032 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003033 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003034 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003035 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003036 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003037 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003038 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003039 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003040 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3041 "event selector. use 'perf list' to list available events",
3042 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003043 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3044 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003045 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003046 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003047 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003048 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003049 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3050 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003051 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003052 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003053 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3054 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003055 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003056 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003057 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003058 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003059 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003060 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003061 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3062 "number of mmap data pages",
3063 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003064 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003065 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003066 OPT_CALLBACK(0, "duration", &trace, "float",
3067 "show only events with duration > N.M ms",
3068 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003069 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003070 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003071 OPT_BOOLEAN('T', "time", &trace.full_time,
3072 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003073 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3074 "Show only syscall summary with statistics"),
3075 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3076 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003077 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3078 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003079 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003080 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003081 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3082 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003083 OPT_END()
3084 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003085 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003086 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003087 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003088
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003089 signal(SIGSEGV, sighandler_dump_stack);
3090 signal(SIGFPE, sighandler_dump_stack);
3091
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003092 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003093
3094 if (trace.evlist == NULL) {
3095 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003096 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003097 goto out;
3098 }
3099
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003100 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3101 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003102
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003103 if (trace.trace_pgfaults) {
3104 trace.opts.sample_address = true;
3105 trace.opts.sample_time = true;
3106 }
3107
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003108 if (trace.evlist->nr_entries > 0)
3109 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3110
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003111 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3112 return trace__record(&trace, argc-1, &argv[1]);
3113
3114 /* summary_only implies summary option, but don't overwrite summary if set */
3115 if (trace.summary_only)
3116 trace.summary = trace.summary_only;
3117
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003118 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3119 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003120 pr_err("Please specify something to trace.\n");
3121 return -1;
3122 }
3123
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003124 if (output_name != NULL) {
3125 err = trace__open_output(&trace, output_name);
3126 if (err < 0) {
3127 perror("failed to create output file");
3128 goto out;
3129 }
3130 }
3131
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003132 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003133 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003134 struct strlist_config slist_config = {
3135 .dirname = system_path(STRACE_GROUPS_DIR),
3136 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003137
3138 trace.not_ev_qualifier = *s == '!';
3139 if (trace.not_ev_qualifier)
3140 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03003141 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003142 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003143 fputs("Not enough memory to parse event qualifier",
3144 trace.output);
3145 err = -ENOMEM;
3146 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003147 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003148
3149 err = trace__validate_ev_qualifier(&trace);
3150 if (err)
3151 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003152 }
3153
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003154 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003155 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003156 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003157 fprintf(trace.output, "%s", bf);
3158 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003159 }
3160
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003161 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003162 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003163 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003164 fprintf(trace.output, "%s", bf);
3165 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003166 }
3167
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003168 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003169 trace.opts.target.system_wide = true;
3170
David Ahern6810fc92013-08-28 22:29:52 -06003171 if (input_name)
3172 err = trace__replay(&trace);
3173 else
3174 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003175
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003176out_close:
3177 if (output_name != NULL)
3178 fclose(trace.output);
3179out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003180 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003181}