blob: 2156532741023b91f25b44ab2630185bcf1950f6 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -030025#include "util/exec_cmd.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030029#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030036
37#include <libaudit.h>
38#include <stdlib.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030039#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030040#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030041
Ingo Molnar456857b2013-09-12 15:29:00 +020042/* For older distros: */
43#ifndef MAP_STACK
44# define MAP_STACK 0x20000
45#endif
46
47#ifndef MADV_HWPOISON
48# define MADV_HWPOISON 100
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -030049
Ingo Molnar456857b2013-09-12 15:29:00 +020050#endif
51
52#ifndef MADV_MERGEABLE
53# define MADV_MERGEABLE 12
54#endif
55
56#ifndef MADV_UNMERGEABLE
57# define MADV_UNMERGEABLE 13
58#endif
59
Ben Hutchings79d26a62014-02-06 01:00:35 +000060#ifndef EFD_SEMAPHORE
61# define EFD_SEMAPHORE 1
62#endif
63
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030064#ifndef EFD_NONBLOCK
65# define EFD_NONBLOCK 00004000
66#endif
67
68#ifndef EFD_CLOEXEC
69# define EFD_CLOEXEC 02000000
70#endif
71
72#ifndef O_CLOEXEC
73# define O_CLOEXEC 02000000
74#endif
75
76#ifndef SOCK_DCCP
77# define SOCK_DCCP 6
78#endif
79
80#ifndef SOCK_CLOEXEC
81# define SOCK_CLOEXEC 02000000
82#endif
83
84#ifndef SOCK_NONBLOCK
85# define SOCK_NONBLOCK 00004000
86#endif
87
88#ifndef MSG_CMSG_CLOEXEC
89# define MSG_CMSG_CLOEXEC 0x40000000
90#endif
91
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -030092#ifndef PERF_FLAG_FD_NO_GROUP
93# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
94#endif
95
96#ifndef PERF_FLAG_FD_OUTPUT
97# define PERF_FLAG_FD_OUTPUT (1UL << 1)
98#endif
99
100#ifndef PERF_FLAG_PID_CGROUP
101# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
102#endif
103
104#ifndef PERF_FLAG_FD_CLOEXEC
105# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
106#endif
107
108
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300109struct tp_field {
110 int offset;
111 union {
112 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
113 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
114 };
115};
116
117#define TP_UINT_FIELD(bits) \
118static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
119{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500120 u##bits value; \
121 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
122 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300123}
124
125TP_UINT_FIELD(8);
126TP_UINT_FIELD(16);
127TP_UINT_FIELD(32);
128TP_UINT_FIELD(64);
129
130#define TP_UINT_FIELD__SWAPPED(bits) \
131static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
132{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500133 u##bits value; \
134 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300135 return bswap_##bits(value);\
136}
137
138TP_UINT_FIELD__SWAPPED(16);
139TP_UINT_FIELD__SWAPPED(32);
140TP_UINT_FIELD__SWAPPED(64);
141
142static int tp_field__init_uint(struct tp_field *field,
143 struct format_field *format_field,
144 bool needs_swap)
145{
146 field->offset = format_field->offset;
147
148 switch (format_field->size) {
149 case 1:
150 field->integer = tp_field__u8;
151 break;
152 case 2:
153 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
154 break;
155 case 4:
156 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
157 break;
158 case 8:
159 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
160 break;
161 default:
162 return -1;
163 }
164
165 return 0;
166}
167
168static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
169{
170 return sample->raw_data + field->offset;
171}
172
173static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
174{
175 field->offset = format_field->offset;
176 field->pointer = tp_field__ptr;
177 return 0;
178}
179
180struct syscall_tp {
181 struct tp_field id;
182 union {
183 struct tp_field args, ret;
184 };
185};
186
187static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
188 struct tp_field *field,
189 const char *name)
190{
191 struct format_field *format_field = perf_evsel__field(evsel, name);
192
193 if (format_field == NULL)
194 return -1;
195
196 return tp_field__init_uint(field, format_field, evsel->needs_swap);
197}
198
199#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
200 ({ struct syscall_tp *sc = evsel->priv;\
201 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
202
203static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
204 struct tp_field *field,
205 const char *name)
206{
207 struct format_field *format_field = perf_evsel__field(evsel, name);
208
209 if (format_field == NULL)
210 return -1;
211
212 return tp_field__init_ptr(field, format_field);
213}
214
215#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
216 ({ struct syscall_tp *sc = evsel->priv;\
217 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
218
219static void perf_evsel__delete_priv(struct perf_evsel *evsel)
220{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300221 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300222 perf_evsel__delete(evsel);
223}
224
Namhyung Kim96695d42013-11-12 08:51:45 -0300225static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
226{
227 evsel->priv = malloc(sizeof(struct syscall_tp));
228 if (evsel->priv != NULL) {
229 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
230 goto out_delete;
231
232 evsel->handler = handler;
233 return 0;
234 }
235
236 return -ENOMEM;
237
238out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300239 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300240 return -ENOENT;
241}
242
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300243static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300244{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300245 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300246
David Ahern9aca7f12013-12-04 19:41:39 -0700247 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
248 if (evsel == NULL)
249 evsel = perf_evsel__newtp("syscalls", direction);
250
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300251 if (evsel) {
Namhyung Kim96695d42013-11-12 08:51:45 -0300252 if (perf_evsel__init_syscall_tp(evsel, handler))
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300253 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300254 }
255
256 return evsel;
257
258out_delete:
259 perf_evsel__delete_priv(evsel);
260 return NULL;
261}
262
263#define perf_evsel__sc_tp_uint(evsel, name, sample) \
264 ({ struct syscall_tp *fields = evsel->priv; \
265 fields->name.integer(&fields->name, sample); })
266
267#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
268 ({ struct syscall_tp *fields = evsel->priv; \
269 fields->name.pointer(&fields->name, sample); })
270
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271struct syscall_arg {
272 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300273 struct thread *thread;
274 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300275 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300276 u8 idx;
277 u8 mask;
278};
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300281 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282 int nr_entries;
283 const char **entries;
284};
285
286#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
287 .nr_entries = ARRAY_SIZE(array), \
288 .entries = array, \
289}
290
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300291#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
292 .offset = off, \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300297static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
298 const char *intfmt,
299 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300302 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303
304 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300305 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306
307 return scnprintf(bf, size, "%s", sa->entries[idx]);
308}
309
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300310static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
311 struct syscall_arg *arg)
312{
313 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
314}
315
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316#define SCA_STRARRAY syscall_arg__scnprintf_strarray
317
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300318#if defined(__i386__) || defined(__x86_64__)
319/*
320 * FIXME: Make this available to all arches as soon as the ioctl beautifier
321 * gets rewritten to support all arches.
322 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300323static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
324 struct syscall_arg *arg)
325{
326 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
327}
328
329#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300330#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300331
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300332static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
333 struct syscall_arg *arg);
334
335#define SCA_FD syscall_arg__scnprintf_fd
336
337static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
338 struct syscall_arg *arg)
339{
340 int fd = arg->val;
341
342 if (fd == AT_FDCWD)
343 return scnprintf(bf, size, "CWD");
344
345 return syscall_arg__scnprintf_fd(bf, size, arg);
346}
347
348#define SCA_FDAT syscall_arg__scnprintf_fd_at
349
350static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
351 struct syscall_arg *arg);
352
353#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
354
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300355static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300356 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300357{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300358 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300359}
360
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300361#define SCA_HEX syscall_arg__scnprintf_hex
362
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300363static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
364 struct syscall_arg *arg)
365{
366 return scnprintf(bf, size, "%d", arg->val);
367}
368
369#define SCA_INT syscall_arg__scnprintf_int
370
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300371static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300372 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300373{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300374 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300375
376 if (prot == PROT_NONE)
377 return scnprintf(bf, size, "NONE");
378#define P_MMAP_PROT(n) \
379 if (prot & PROT_##n) { \
380 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
381 prot &= ~PROT_##n; \
382 }
383
384 P_MMAP_PROT(EXEC);
385 P_MMAP_PROT(READ);
386 P_MMAP_PROT(WRITE);
387#ifdef PROT_SEM
388 P_MMAP_PROT(SEM);
389#endif
390 P_MMAP_PROT(GROWSDOWN);
391 P_MMAP_PROT(GROWSUP);
392#undef P_MMAP_PROT
393
394 if (prot)
395 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
396
397 return printed;
398}
399
400#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
401
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300402static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300403 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300404{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300405 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300406
407#define P_MMAP_FLAG(n) \
408 if (flags & MAP_##n) { \
409 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
410 flags &= ~MAP_##n; \
411 }
412
413 P_MMAP_FLAG(SHARED);
414 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400415#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300416 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400417#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300418 P_MMAP_FLAG(ANONYMOUS);
419 P_MMAP_FLAG(DENYWRITE);
420 P_MMAP_FLAG(EXECUTABLE);
421 P_MMAP_FLAG(FILE);
422 P_MMAP_FLAG(FIXED);
423 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600424#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300425 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600426#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300427 P_MMAP_FLAG(LOCKED);
428 P_MMAP_FLAG(NONBLOCK);
429 P_MMAP_FLAG(NORESERVE);
430 P_MMAP_FLAG(POPULATE);
431 P_MMAP_FLAG(STACK);
432#ifdef MAP_UNINITIALIZED
433 P_MMAP_FLAG(UNINITIALIZED);
434#endif
435#undef P_MMAP_FLAG
436
437 if (flags)
438 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
439
440 return printed;
441}
442
443#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
444
Alex Snast86998dd2014-08-13 18:42:40 +0300445static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
446 struct syscall_arg *arg)
447{
448 int printed = 0, flags = arg->val;
449
450#define P_MREMAP_FLAG(n) \
451 if (flags & MREMAP_##n) { \
452 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
453 flags &= ~MREMAP_##n; \
454 }
455
456 P_MREMAP_FLAG(MAYMOVE);
457#ifdef MREMAP_FIXED
458 P_MREMAP_FLAG(FIXED);
459#endif
460#undef P_MREMAP_FLAG
461
462 if (flags)
463 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
464
465 return printed;
466}
467
468#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
469
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300470static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300471 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300472{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300473 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300474
475 switch (behavior) {
476#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
477 P_MADV_BHV(NORMAL);
478 P_MADV_BHV(RANDOM);
479 P_MADV_BHV(SEQUENTIAL);
480 P_MADV_BHV(WILLNEED);
481 P_MADV_BHV(DONTNEED);
482 P_MADV_BHV(REMOVE);
483 P_MADV_BHV(DONTFORK);
484 P_MADV_BHV(DOFORK);
485 P_MADV_BHV(HWPOISON);
486#ifdef MADV_SOFT_OFFLINE
487 P_MADV_BHV(SOFT_OFFLINE);
488#endif
489 P_MADV_BHV(MERGEABLE);
490 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600491#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300492 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600493#endif
494#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300495 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600496#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300497#ifdef MADV_DONTDUMP
498 P_MADV_BHV(DONTDUMP);
499#endif
500#ifdef MADV_DODUMP
501 P_MADV_BHV(DODUMP);
502#endif
503#undef P_MADV_PHV
504 default: break;
505 }
506
507 return scnprintf(bf, size, "%#x", behavior);
508}
509
510#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
511
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300512static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
513 struct syscall_arg *arg)
514{
515 int printed = 0, op = arg->val;
516
517 if (op == 0)
518 return scnprintf(bf, size, "NONE");
519#define P_CMD(cmd) \
520 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
521 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
522 op &= ~LOCK_##cmd; \
523 }
524
525 P_CMD(SH);
526 P_CMD(EX);
527 P_CMD(NB);
528 P_CMD(UN);
529 P_CMD(MAND);
530 P_CMD(RW);
531 P_CMD(READ);
532 P_CMD(WRITE);
533#undef P_OP
534
535 if (op)
536 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
537
538 return printed;
539}
540
541#define SCA_FLOCK syscall_arg__scnprintf_flock
542
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300543static 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 -0300544{
545 enum syscall_futex_args {
546 SCF_UADDR = (1 << 0),
547 SCF_OP = (1 << 1),
548 SCF_VAL = (1 << 2),
549 SCF_TIMEOUT = (1 << 3),
550 SCF_UADDR2 = (1 << 4),
551 SCF_VAL3 = (1 << 5),
552 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300553 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300554 int cmd = op & FUTEX_CMD_MASK;
555 size_t printed = 0;
556
557 switch (cmd) {
558#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300559 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
560 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
561 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
562 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
563 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
564 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300565 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300566 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
567 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
568 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
569 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
570 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300571 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
572 default: printed = scnprintf(bf, size, "%#x", cmd); break;
573 }
574
575 if (op & FUTEX_PRIVATE_FLAG)
576 printed += scnprintf(bf + printed, size - printed, "|PRIV");
577
578 if (op & FUTEX_CLOCK_REALTIME)
579 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
580
581 return printed;
582}
583
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300584#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
585
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300586static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
587static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300588
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300589static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
590static DEFINE_STRARRAY(itimers);
591
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300592static const char *keyctl_options[] = {
593 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
594 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
595 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
596 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
597 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
598};
599static DEFINE_STRARRAY(keyctl_options);
600
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300601static const char *whences[] = { "SET", "CUR", "END",
602#ifdef SEEK_DATA
603"DATA",
604#endif
605#ifdef SEEK_HOLE
606"HOLE",
607#endif
608};
609static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300610
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300611static const char *fcntl_cmds[] = {
612 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
613 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
614 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
615 "F_GETOWNER_UIDS",
616};
617static DEFINE_STRARRAY(fcntl_cmds);
618
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300619static const char *rlimit_resources[] = {
620 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
621 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
622 "RTTIME",
623};
624static DEFINE_STRARRAY(rlimit_resources);
625
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300626static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
627static DEFINE_STRARRAY(sighow);
628
David Ahern4f8c1b72013-09-22 19:45:00 -0600629static const char *clockid[] = {
630 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300631 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
632 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600633};
634static DEFINE_STRARRAY(clockid);
635
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300636static const char *socket_families[] = {
637 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
638 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
639 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
640 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
641 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
642 "ALG", "NFC", "VSOCK",
643};
644static DEFINE_STRARRAY(socket_families);
645
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300646#ifndef SOCK_TYPE_MASK
647#define SOCK_TYPE_MASK 0xf
648#endif
649
650static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
651 struct syscall_arg *arg)
652{
653 size_t printed;
654 int type = arg->val,
655 flags = type & ~SOCK_TYPE_MASK;
656
657 type &= SOCK_TYPE_MASK;
658 /*
659 * Can't use a strarray, MIPS may override for ABI reasons.
660 */
661 switch (type) {
662#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
663 P_SK_TYPE(STREAM);
664 P_SK_TYPE(DGRAM);
665 P_SK_TYPE(RAW);
666 P_SK_TYPE(RDM);
667 P_SK_TYPE(SEQPACKET);
668 P_SK_TYPE(DCCP);
669 P_SK_TYPE(PACKET);
670#undef P_SK_TYPE
671 default:
672 printed = scnprintf(bf, size, "%#x", type);
673 }
674
675#define P_SK_FLAG(n) \
676 if (flags & SOCK_##n) { \
677 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
678 flags &= ~SOCK_##n; \
679 }
680
681 P_SK_FLAG(CLOEXEC);
682 P_SK_FLAG(NONBLOCK);
683#undef P_SK_FLAG
684
685 if (flags)
686 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
687
688 return printed;
689}
690
691#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
692
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300693#ifndef MSG_PROBE
694#define MSG_PROBE 0x10
695#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600696#ifndef MSG_WAITFORONE
697#define MSG_WAITFORONE 0x10000
698#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300699#ifndef MSG_SENDPAGE_NOTLAST
700#define MSG_SENDPAGE_NOTLAST 0x20000
701#endif
702#ifndef MSG_FASTOPEN
703#define MSG_FASTOPEN 0x20000000
704#endif
705
706static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
707 struct syscall_arg *arg)
708{
709 int printed = 0, flags = arg->val;
710
711 if (flags == 0)
712 return scnprintf(bf, size, "NONE");
713#define P_MSG_FLAG(n) \
714 if (flags & MSG_##n) { \
715 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
716 flags &= ~MSG_##n; \
717 }
718
719 P_MSG_FLAG(OOB);
720 P_MSG_FLAG(PEEK);
721 P_MSG_FLAG(DONTROUTE);
722 P_MSG_FLAG(TRYHARD);
723 P_MSG_FLAG(CTRUNC);
724 P_MSG_FLAG(PROBE);
725 P_MSG_FLAG(TRUNC);
726 P_MSG_FLAG(DONTWAIT);
727 P_MSG_FLAG(EOR);
728 P_MSG_FLAG(WAITALL);
729 P_MSG_FLAG(FIN);
730 P_MSG_FLAG(SYN);
731 P_MSG_FLAG(CONFIRM);
732 P_MSG_FLAG(RST);
733 P_MSG_FLAG(ERRQUEUE);
734 P_MSG_FLAG(NOSIGNAL);
735 P_MSG_FLAG(MORE);
736 P_MSG_FLAG(WAITFORONE);
737 P_MSG_FLAG(SENDPAGE_NOTLAST);
738 P_MSG_FLAG(FASTOPEN);
739 P_MSG_FLAG(CMSG_CLOEXEC);
740#undef P_MSG_FLAG
741
742 if (flags)
743 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
744
745 return printed;
746}
747
748#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
749
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300750static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
751 struct syscall_arg *arg)
752{
753 size_t printed = 0;
754 int mode = arg->val;
755
756 if (mode == F_OK) /* 0 */
757 return scnprintf(bf, size, "F");
758#define P_MODE(n) \
759 if (mode & n##_OK) { \
760 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
761 mode &= ~n##_OK; \
762 }
763
764 P_MODE(R);
765 P_MODE(W);
766 P_MODE(X);
767#undef P_MODE
768
769 if (mode)
770 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
771
772 return printed;
773}
774
775#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
776
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300777static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
778 struct syscall_arg *arg);
779
780#define SCA_FILENAME syscall_arg__scnprintf_filename
781
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300782static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300783 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300784{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300785 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300786
787 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300788 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300789
790 if (flags == 0)
791 return scnprintf(bf, size, "RDONLY");
792#define P_FLAG(n) \
793 if (flags & O_##n) { \
794 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
795 flags &= ~O_##n; \
796 }
797
798 P_FLAG(APPEND);
799 P_FLAG(ASYNC);
800 P_FLAG(CLOEXEC);
801 P_FLAG(CREAT);
802 P_FLAG(DIRECT);
803 P_FLAG(DIRECTORY);
804 P_FLAG(EXCL);
805 P_FLAG(LARGEFILE);
806 P_FLAG(NOATIME);
807 P_FLAG(NOCTTY);
808#ifdef O_NONBLOCK
809 P_FLAG(NONBLOCK);
810#elif O_NDELAY
811 P_FLAG(NDELAY);
812#endif
813#ifdef O_PATH
814 P_FLAG(PATH);
815#endif
816 P_FLAG(RDWR);
817#ifdef O_DSYNC
818 if ((flags & O_SYNC) == O_SYNC)
819 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
820 else {
821 P_FLAG(DSYNC);
822 }
823#else
824 P_FLAG(SYNC);
825#endif
826 P_FLAG(TRUNC);
827 P_FLAG(WRONLY);
828#undef P_FLAG
829
830 if (flags)
831 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
832
833 return printed;
834}
835
836#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
837
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300838static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
839 struct syscall_arg *arg)
840{
841 int printed = 0, flags = arg->val;
842
843 if (flags == 0)
844 return 0;
845
846#define P_FLAG(n) \
847 if (flags & PERF_FLAG_##n) { \
848 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
849 flags &= ~PERF_FLAG_##n; \
850 }
851
852 P_FLAG(FD_NO_GROUP);
853 P_FLAG(FD_OUTPUT);
854 P_FLAG(PID_CGROUP);
855 P_FLAG(FD_CLOEXEC);
856#undef P_FLAG
857
858 if (flags)
859 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
860
861 return printed;
862}
863
864#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
865
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300866static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
867 struct syscall_arg *arg)
868{
869 int printed = 0, flags = arg->val;
870
871 if (flags == 0)
872 return scnprintf(bf, size, "NONE");
873#define P_FLAG(n) \
874 if (flags & EFD_##n) { \
875 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
876 flags &= ~EFD_##n; \
877 }
878
879 P_FLAG(SEMAPHORE);
880 P_FLAG(CLOEXEC);
881 P_FLAG(NONBLOCK);
882#undef P_FLAG
883
884 if (flags)
885 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
886
887 return printed;
888}
889
890#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
891
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300892static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
893 struct syscall_arg *arg)
894{
895 int printed = 0, flags = arg->val;
896
897#define P_FLAG(n) \
898 if (flags & O_##n) { \
899 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
900 flags &= ~O_##n; \
901 }
902
903 P_FLAG(CLOEXEC);
904 P_FLAG(NONBLOCK);
905#undef P_FLAG
906
907 if (flags)
908 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
909
910 return printed;
911}
912
913#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
914
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300915static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
916{
917 int sig = arg->val;
918
919 switch (sig) {
920#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
921 P_SIGNUM(HUP);
922 P_SIGNUM(INT);
923 P_SIGNUM(QUIT);
924 P_SIGNUM(ILL);
925 P_SIGNUM(TRAP);
926 P_SIGNUM(ABRT);
927 P_SIGNUM(BUS);
928 P_SIGNUM(FPE);
929 P_SIGNUM(KILL);
930 P_SIGNUM(USR1);
931 P_SIGNUM(SEGV);
932 P_SIGNUM(USR2);
933 P_SIGNUM(PIPE);
934 P_SIGNUM(ALRM);
935 P_SIGNUM(TERM);
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300936 P_SIGNUM(CHLD);
937 P_SIGNUM(CONT);
938 P_SIGNUM(STOP);
939 P_SIGNUM(TSTP);
940 P_SIGNUM(TTIN);
941 P_SIGNUM(TTOU);
942 P_SIGNUM(URG);
943 P_SIGNUM(XCPU);
944 P_SIGNUM(XFSZ);
945 P_SIGNUM(VTALRM);
946 P_SIGNUM(PROF);
947 P_SIGNUM(WINCH);
948 P_SIGNUM(IO);
949 P_SIGNUM(PWR);
950 P_SIGNUM(SYS);
Ben Hutchings02c5bb42014-02-06 01:00:41 +0000951#ifdef SIGEMT
952 P_SIGNUM(EMT);
953#endif
954#ifdef SIGSTKFLT
955 P_SIGNUM(STKFLT);
956#endif
957#ifdef SIGSWI
958 P_SIGNUM(SWI);
959#endif
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300960 default: break;
961 }
962
963 return scnprintf(bf, size, "%#x", sig);
964}
965
966#define SCA_SIGNUM syscall_arg__scnprintf_signum
967
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300968#if defined(__i386__) || defined(__x86_64__)
969/*
970 * FIXME: Make this available to all arches.
971 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300972#define TCGETS 0x5401
973
974static const char *tioctls[] = {
975 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
976 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
977 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
978 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
979 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
980 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
981 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
982 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
983 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
984 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
985 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
986 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
987 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
988 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
989 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
990};
991
992static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300993#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300994
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300995#define STRARRAY(arg, name, array) \
996 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
997 .arg_parm = { [arg] = &strarray__##array, }
998
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300999static struct syscall_fmt {
1000 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001001 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001002 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001003 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001004 bool errmsg;
1005 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001006 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001007} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -03001008 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001009 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1010 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001011 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001012 { .name = "brk", .hexret = true,
1013 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001014 { .name = "chdir", .errmsg = true,
1015 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1016 { .name = "chmod", .errmsg = true,
1017 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1018 { .name = "chroot", .errmsg = true,
1019 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -06001020 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001022 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -03001023 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001024 { .name = "creat", .errmsg = true,
1025 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001026 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001027 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001028 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001029 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001030 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001031 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001032 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -03001033 { .name = "eventfd2", .errmsg = true,
1034 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001035 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001036 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1037 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001038 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001039 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001040 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001041 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001042 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001043 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001044 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001045 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001046 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001047 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1048 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001049 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001050 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001051 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001052 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1053 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054 { .name = "fcntl", .errmsg = true,
1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1056 [1] = SCA_STRARRAY, /* cmd */ },
1057 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1058 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001059 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -03001060 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001061 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1062 [1] = SCA_FLOCK, /* cmd */ }, },
1063 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001064 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001065 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001066 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001067 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001068 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1069 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001070 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001071 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001072 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001073 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001074 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001075 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -03001076 { .name = "futex", .errmsg = true,
1077 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001078 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001079 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1080 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001081 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001082 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001083 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001084 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001085 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1086 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001087 { .name = "getxattr", .errmsg = true,
1088 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1089 { .name = "inotify_add_watch", .errmsg = true,
1090 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001091 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001092 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001093#if defined(__i386__) || defined(__x86_64__)
1094/*
1095 * FIXME: Make this available to all arches.
1096 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -03001097 [1] = SCA_STRHEXARRAY, /* cmd */
1098 [2] = SCA_HEX, /* arg */ },
1099 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -03001100#else
1101 [2] = SCA_HEX, /* arg */ }, },
1102#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -03001103 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001104 { .name = "kill", .errmsg = true,
1105 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001106 { .name = "lchown", .errmsg = true,
1107 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1108 { .name = "lgetxattr", .errmsg = true,
1109 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001110 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001111 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001112 { .name = "listxattr", .errmsg = true,
1113 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001114 { .name = "llistxattr", .errmsg = true,
1115 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1116 { .name = "lremovexattr", .errmsg = true,
1117 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001118 { .name = "lseek", .errmsg = true,
1119 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1120 [2] = SCA_STRARRAY, /* whence */ },
1121 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001122 { .name = "lsetxattr", .errmsg = true,
1123 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001124 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1125 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001126 { .name = "lsxattr", .errmsg = true,
1127 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -03001128 { .name = "madvise", .errmsg = true,
1129 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1130 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001131 { .name = "mkdir", .errmsg = true,
1132 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001133 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001134 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1135 [1] = SCA_FILENAME, /* pathname */ }, },
1136 { .name = "mknod", .errmsg = true,
1137 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001138 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001139 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1140 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001141 { .name = "mlock", .errmsg = true,
1142 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1143 { .name = "mlockall", .errmsg = true,
1144 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001145 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001146 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -03001147 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +09001148 [3] = SCA_MMAP_FLAGS, /* flags */
1149 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001150 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001151 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1152 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001153 { .name = "mq_unlink", .errmsg = true,
1154 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001155 { .name = "mremap", .hexret = true,
1156 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +03001157 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -03001158 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -03001159 { .name = "munlock", .errmsg = true,
1160 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001161 { .name = "munmap", .errmsg = true,
1162 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001163 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001164 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001165 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001166 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1167 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -03001168 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001169 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1170 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001171 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001172 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1173 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -03001174 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001175 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001176 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001177 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -03001178 { .name = "perf_event_open", .errmsg = true,
1179 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1180 [2] = SCA_INT, /* cpu */
1181 [3] = SCA_FD, /* group_fd */
1182 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -03001183 { .name = "pipe2", .errmsg = true,
1184 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001185 { .name = "poll", .errmsg = true, .timeout = true, },
1186 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001187 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001188 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001189 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001190 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001191 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001192 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001193 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001194 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001195 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001196 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001197 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001198 { .name = "readlink", .errmsg = true,
1199 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001200 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001201 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1202 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001203 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001204 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001205 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001206 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1207 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001208 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001209 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1210 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001211 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001212 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1213 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001214 { .name = "removexattr", .errmsg = true,
1215 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001216 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001217 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001218 { .name = "rmdir", .errmsg = true,
1219 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001220 { .name = "rt_sigaction", .errmsg = true,
1221 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001222 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001223 { .name = "rt_sigqueueinfo", .errmsg = true,
1224 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1225 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1226 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001227 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001228 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001229 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1230 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001231 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001232 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1233 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -03001234 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -03001235 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1236 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -03001237 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1238 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001239 { .name = "setxattr", .errmsg = true,
1240 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001241 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001242 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001243 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -03001244 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1245 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -03001246 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -03001247 { .name = "socketpair", .errmsg = true,
1248 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1249 [1] = SCA_SK_TYPE, /* type */ },
1250 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001251 { .name = "stat", .errmsg = true, .alias = "newstat",
1252 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001253 { .name = "statfs", .errmsg = true,
1254 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1255 { .name = "swapoff", .errmsg = true,
1256 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1257 { .name = "swapon", .errmsg = true,
1258 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001259 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001260 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -03001261 { .name = "tgkill", .errmsg = true,
1262 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1263 { .name = "tkill", .errmsg = true,
1264 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001265 { .name = "truncate", .errmsg = true,
1266 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -03001267 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001268 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001269 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1270 [1] = SCA_FILENAME, /* pathname */ }, },
1271 { .name = "utime", .errmsg = true,
1272 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001273 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -03001274 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1275 [1] = SCA_FILENAME, /* filename */ }, },
1276 { .name = "utimes", .errmsg = true,
1277 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -03001278 { .name = "vmsplice", .errmsg = true,
1279 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001280 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001281 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001282 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001283 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001284};
1285
1286static int syscall_fmt__cmp(const void *name, const void *fmtp)
1287{
1288 const struct syscall_fmt *fmt = fmtp;
1289 return strcmp(name, fmt->name);
1290}
1291
1292static struct syscall_fmt *syscall_fmt__find(const char *name)
1293{
1294 const int nmemb = ARRAY_SIZE(syscall_fmts);
1295 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1296}
1297
1298struct syscall {
1299 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001300 int nr_args;
1301 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001302 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001303 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001304 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001305 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001306 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001307};
1308
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001309static size_t fprintf_duration(unsigned long t, FILE *fp)
1310{
1311 double duration = (double)t / NSEC_PER_MSEC;
1312 size_t printed = fprintf(fp, "(");
1313
1314 if (duration >= 1.0)
1315 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1316 else if (duration >= 0.01)
1317 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1318 else
1319 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001320 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001321}
1322
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001323/**
1324 * filename.ptr: The filename char pointer that will be vfs_getname'd
1325 * filename.entry_str_pos: Where to insert the string translated from
1326 * filename.ptr by the vfs_getname tracepoint/kprobe.
1327 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001328struct thread_trace {
1329 u64 entry_time;
1330 u64 exit_time;
1331 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001332 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001333 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001334 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001335 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001336 struct {
1337 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001338 short int entry_str_pos;
1339 bool pending_open;
1340 unsigned int namelen;
1341 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001342 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001343 struct {
1344 int max;
1345 char **table;
1346 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -06001347
1348 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001349};
1350
1351static struct thread_trace *thread_trace__new(void)
1352{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001353 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1354
1355 if (ttrace)
1356 ttrace->paths.max = -1;
1357
David Ahernbf2575c2013-10-08 21:26:53 -06001358 ttrace->syscall_stats = intlist__new(NULL);
1359
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001360 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001361}
1362
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001363static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001364{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001365 struct thread_trace *ttrace;
1366
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001367 if (thread == NULL)
1368 goto fail;
1369
Namhyung Kim89dceb22014-10-06 09:46:03 +09001370 if (thread__priv(thread) == NULL)
1371 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -03001372
Namhyung Kim89dceb22014-10-06 09:46:03 +09001373 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001374 goto fail;
1375
Namhyung Kim89dceb22014-10-06 09:46:03 +09001376 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001377 ++ttrace->nr_events;
1378
1379 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001380fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001381 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001382 "WARNING: not enough memory, dropping samples!\n");
1383 return NULL;
1384}
1385
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001386#define TRACE_PFMAJ (1 << 0)
1387#define TRACE_PFMIN (1 << 1)
1388
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001389static const size_t trace__entry_str_size = 2048;
1390
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001392 struct perf_tool tool;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001393 struct {
1394 int machine;
1395 int open_id;
1396 } audit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001397 struct {
1398 int max;
1399 struct syscall *table;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001400 struct {
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001401 struct perf_evsel *sys_enter,
1402 *sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03001403 } events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001404 } syscalls;
Arnaldo Carvalho de Melob4006792013-12-19 14:43:45 -03001405 struct record_opts opts;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001406 struct perf_evlist *evlist;
David Ahern8fb598e2013-09-28 13:13:00 -06001407 struct machine *host;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001408 struct thread *current;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001409 u64 base_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001410 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001411 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001412 struct strlist *ev_qualifier;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001413 struct {
1414 size_t nr;
1415 int *entries;
1416 } ev_qualifier_ids;
David Ahernbdc89662013-08-28 22:29:53 -06001417 struct intlist *tid_list;
1418 struct intlist *pid_list;
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08001419 struct {
1420 size_t nr;
1421 pid_t *entries;
1422 } filter_pids;
Arnaldo Carvalho de Melo98eafce2014-01-06 15:43:02 -03001423 double duration_filter;
1424 double runtime_ms;
1425 struct {
1426 u64 vfs_getname,
1427 proc_getname;
1428 } stats;
1429 bool not_ev_qualifier;
1430 bool live;
1431 bool full_time;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001432 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001433 bool multiple_threads;
David Ahernbf2575c2013-10-08 21:26:53 -06001434 bool summary;
David Ahernfd2eaba2013-11-12 09:31:15 -07001435 bool summary_only;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001436 bool show_comm;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001437 bool show_tool_stats;
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001438 bool trace_syscalls;
Yunlong Songe366a6d2015-04-02 21:47:18 +08001439 bool force;
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03001440 bool vfs_getname;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001441 int trace_pgfaults;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001442};
1443
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001444static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001445{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001446 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001447
1448 if (fd > ttrace->paths.max) {
1449 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1450
1451 if (npath == NULL)
1452 return -1;
1453
1454 if (ttrace->paths.max != -1) {
1455 memset(npath + ttrace->paths.max + 1, 0,
1456 (fd - ttrace->paths.max) * sizeof(char *));
1457 } else {
1458 memset(npath, 0, (fd + 1) * sizeof(char *));
1459 }
1460
1461 ttrace->paths.table = npath;
1462 ttrace->paths.max = fd;
1463 }
1464
1465 ttrace->paths.table[fd] = strdup(pathname);
1466
1467 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1468}
1469
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001470static int thread__read_fd_path(struct thread *thread, int fd)
1471{
1472 char linkname[PATH_MAX], pathname[PATH_MAX];
1473 struct stat st;
1474 int ret;
1475
1476 if (thread->pid_ == thread->tid) {
1477 scnprintf(linkname, sizeof(linkname),
1478 "/proc/%d/fd/%d", thread->pid_, fd);
1479 } else {
1480 scnprintf(linkname, sizeof(linkname),
1481 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1482 }
1483
1484 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1485 return -1;
1486
1487 ret = readlink(linkname, pathname, sizeof(pathname));
1488
1489 if (ret < 0 || ret > st.st_size)
1490 return -1;
1491
1492 pathname[ret] = '\0';
1493 return trace__set_fd_pathname(thread, fd, pathname);
1494}
1495
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001496static const char *thread__fd_path(struct thread *thread, int fd,
1497 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001498{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001499 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001500
1501 if (ttrace == NULL)
1502 return NULL;
1503
1504 if (fd < 0)
1505 return NULL;
1506
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001507 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001508 if (!trace->live)
1509 return NULL;
1510 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001511 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001512 return NULL;
1513 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001514
1515 return ttrace->paths.table[fd];
1516}
1517
1518static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1519 struct syscall_arg *arg)
1520{
1521 int fd = arg->val;
1522 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001523 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001524
1525 if (path)
1526 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1527
1528 return printed;
1529}
1530
1531static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1532 struct syscall_arg *arg)
1533{
1534 int fd = arg->val;
1535 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001536 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001537
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001538 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1539 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001540
1541 return printed;
1542}
1543
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001544static void thread__set_filename_pos(struct thread *thread, const char *bf,
1545 unsigned long ptr)
1546{
1547 struct thread_trace *ttrace = thread__priv(thread);
1548
1549 ttrace->filename.ptr = ptr;
1550 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1551}
1552
1553static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1554 struct syscall_arg *arg)
1555{
1556 unsigned long ptr = arg->val;
1557
1558 if (!arg->trace->vfs_getname)
1559 return scnprintf(bf, size, "%#x", ptr);
1560
1561 thread__set_filename_pos(arg->thread, bf, ptr);
1562 return 0;
1563}
1564
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001565static bool trace__filter_duration(struct trace *trace, double t)
1566{
1567 return t < (trace->duration_filter * NSEC_PER_MSEC);
1568}
1569
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001570static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1571{
1572 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1573
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001574 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001575}
1576
Namhyung Kimf15eb532012-10-05 14:02:16 +09001577static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001578static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001579
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001580static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001581{
1582 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001583 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001584}
1585
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001586static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001587 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001588{
1589 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001590 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001591
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001592 if (trace->multiple_threads) {
1593 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001594 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001595 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001596 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001597
1598 return printed;
1599}
1600
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001601static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001602 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001603{
1604 int ret = 0;
1605
1606 switch (event->header.type) {
1607 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001608 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001609 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001610 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001611 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001612 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001613 break;
1614 }
1615
1616 return ret;
1617}
1618
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001619static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001620 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001621 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001622 struct machine *machine)
1623{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001624 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001625 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001626}
1627
1628static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1629{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001630 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001631
1632 if (err)
1633 return err;
1634
David Ahern8fb598e2013-09-28 13:13:00 -06001635 trace->host = machine__new_host();
1636 if (trace->host == NULL)
1637 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001638
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001639 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001640 return -errno;
1641
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001642 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001643 evlist->threads, trace__tool_process, false,
1644 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001645 if (err)
1646 symbol__exit();
1647
1648 return err;
1649}
1650
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001651static int syscall__set_arg_fmts(struct syscall *sc)
1652{
1653 struct format_field *field;
1654 int idx = 0;
1655
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001656 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001657 if (sc->arg_scnprintf == NULL)
1658 return -1;
1659
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001660 if (sc->fmt)
1661 sc->arg_parm = sc->fmt->arg_parm;
1662
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001663 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001664 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1665 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1666 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001667 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1668 ++idx;
1669 }
1670
1671 return 0;
1672}
1673
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001674static int trace__read_syscall_info(struct trace *trace, int id)
1675{
1676 char tp_name[128];
1677 struct syscall *sc;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001678 const char *name = audit_syscall_to_name(id, trace->audit.machine);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001679
1680 if (name == NULL)
1681 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001682
1683 if (id > trace->syscalls.max) {
1684 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1685
1686 if (nsyscalls == NULL)
1687 return -1;
1688
1689 if (trace->syscalls.max != -1) {
1690 memset(nsyscalls + trace->syscalls.max + 1, 0,
1691 (id - trace->syscalls.max) * sizeof(*sc));
1692 } else {
1693 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1694 }
1695
1696 trace->syscalls.table = nsyscalls;
1697 trace->syscalls.max = id;
1698 }
1699
1700 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001701 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001702
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001703 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001704
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001705 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001706 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001707
1708 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1709 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001710 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001711 }
1712
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001713 if (sc->tp_format == NULL)
1714 return -1;
1715
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001716 sc->args = sc->tp_format->format.fields;
1717 sc->nr_args = sc->tp_format->format.nr_fields;
1718 /* drop nr field - not relevant here; does not exist on older kernels */
1719 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1720 sc->args = sc->args->next;
1721 --sc->nr_args;
1722 }
1723
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001724 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1725
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001726 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001727}
1728
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001729static int trace__validate_ev_qualifier(struct trace *trace)
1730{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001731 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001732 struct str_node *pos;
1733
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001734 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1735 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1736 sizeof(trace->ev_qualifier_ids.entries[0]));
1737
1738 if (trace->ev_qualifier_ids.entries == NULL) {
1739 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1740 trace->output);
1741 err = -EINVAL;
1742 goto out;
1743 }
1744
1745 i = 0;
1746
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001747 strlist__for_each(pos, trace->ev_qualifier) {
1748 const char *sc = pos->s;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001749 int id = audit_name_to_syscall(sc, trace->audit.machine);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001750
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001751 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001752 if (err == 0) {
1753 fputs("Error:\tInvalid syscall ", trace->output);
1754 err = -EINVAL;
1755 } else {
1756 fputs(", ", trace->output);
1757 }
1758
1759 fputs(sc, trace->output);
1760 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001761
1762 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001763 }
1764
1765 if (err < 0) {
1766 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1767 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001768 zfree(&trace->ev_qualifier_ids.entries);
1769 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001770 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001771out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001772 return err;
1773}
1774
David Ahern55d43bc2015-02-19 15:00:22 -05001775/*
1776 * args is to be interpreted as a series of longs but we need to handle
1777 * 8-byte unaligned accesses. args points to raw_data within the event
1778 * and raw_data is guaranteed to be 8-byte unaligned because it is
1779 * preceded by raw_size which is a u32. So we need to copy args to a temp
1780 * variable to read it. Most notably this avoids extended load instructions
1781 * on unaligned addresses
1782 */
1783
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001784static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001785 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001786 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001787{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001788 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001789 unsigned char *p;
1790 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001791
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001792 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001793 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001794 u8 bit = 1;
1795 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001796 .idx = 0,
1797 .mask = 0,
1798 .trace = trace,
1799 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001800 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001801
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001802 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001803 field = field->next, ++arg.idx, bit <<= 1) {
1804 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001805 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001806
1807 /* special care for unaligned accesses */
1808 p = args + sizeof(unsigned long) * arg.idx;
1809 memcpy(&val, p, sizeof(val));
1810
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001811 /*
1812 * Suppress this argument if its value is zero and
1813 * and we don't have a string associated in an
1814 * strarray for it.
1815 */
David Ahern55d43bc2015-02-19 15:00:22 -05001816 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001817 !(sc->arg_scnprintf &&
1818 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1819 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001820 continue;
1821
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001822 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001823 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001824 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001825 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001826 if (sc->arg_parm)
1827 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001828 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1829 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001830 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001831 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001832 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001833 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001834 }
1835 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001836 int i = 0;
1837
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001838 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001839 /* special care for unaligned accesses */
1840 p = args + sizeof(unsigned long) * i;
1841 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001842 printed += scnprintf(bf + printed, size - printed,
1843 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001844 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001845 ++i;
1846 }
1847 }
1848
1849 return printed;
1850}
1851
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001852typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001853 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001854 struct perf_sample *sample);
1855
1856static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001857 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001858{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001859
1860 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001861
1862 /*
1863 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1864 * before that, leaving at a higher verbosity level till that is
1865 * explained. Reproduced with plain ftrace with:
1866 *
1867 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1868 * grep "NR -1 " /t/trace_pipe
1869 *
1870 * After generating some load on the machine.
1871 */
1872 if (verbose > 1) {
1873 static u64 n;
1874 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1875 id, perf_evsel__name(evsel), ++n);
1876 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001877 return NULL;
1878 }
1879
1880 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1881 trace__read_syscall_info(trace, id))
1882 goto out_cant_read;
1883
1884 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1885 goto out_cant_read;
1886
1887 return &trace->syscalls.table[id];
1888
1889out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001890 if (verbose) {
1891 fprintf(trace->output, "Problems reading syscall %d", id);
1892 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1893 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1894 fputs(" information\n", trace->output);
1895 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001896 return NULL;
1897}
1898
David Ahernbf2575c2013-10-08 21:26:53 -06001899static void thread__update_stats(struct thread_trace *ttrace,
1900 int id, struct perf_sample *sample)
1901{
1902 struct int_node *inode;
1903 struct stats *stats;
1904 u64 duration = 0;
1905
1906 inode = intlist__findnew(ttrace->syscall_stats, id);
1907 if (inode == NULL)
1908 return;
1909
1910 stats = inode->priv;
1911 if (stats == NULL) {
1912 stats = malloc(sizeof(struct stats));
1913 if (stats == NULL)
1914 return;
1915 init_stats(stats);
1916 inode->priv = stats;
1917 }
1918
1919 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1920 duration = sample->time - ttrace->entry_time;
1921
1922 update_stats(stats, duration);
1923}
1924
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001925static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1926{
1927 struct thread_trace *ttrace;
1928 u64 duration;
1929 size_t printed;
1930
1931 if (trace->current == NULL)
1932 return 0;
1933
1934 ttrace = thread__priv(trace->current);
1935
1936 if (!ttrace->entry_pending)
1937 return 0;
1938
1939 duration = sample->time - ttrace->entry_time;
1940
1941 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1942 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1943 ttrace->entry_pending = false;
1944
1945 return printed;
1946}
1947
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001948static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001949 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001950 struct perf_sample *sample)
1951{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001952 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001953 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001954 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001955 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001956 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001957 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001958 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001959
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001960 if (sc == NULL)
1961 return -1;
1962
David Ahern8fb598e2013-09-28 13:13:00 -06001963 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001964 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001965 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001966 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001967
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001968 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001969
1970 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001971 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001972 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001973 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001974 }
1975
David Ahern13f22a22015-03-19 12:23:03 -06001976 if (!trace->summary_only)
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001977 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001978
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001979 ttrace->entry_time = sample->time;
1980 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001981 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001982
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001983 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001984 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001985
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001986 if (sc->is_exit) {
David Ahernfd2eaba2013-11-12 09:31:15 -07001987 if (!trace->duration_filter && !trace->summary_only) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001988 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1989 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001990 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001991 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001992 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001993 /* See trace__vfs_getname & trace__sys_exit */
1994 ttrace->filename.pending_open = false;
1995 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001996
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001997 if (trace->current != thread) {
1998 thread__put(trace->current);
1999 trace->current = thread__get(thread);
2000 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002001 err = 0;
2002out_put:
2003 thread__put(thread);
2004 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002005}
2006
2007static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002008 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002009 struct perf_sample *sample)
2010{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002011 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002012 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002013 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002014 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06002015 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002016 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002017
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002018 if (sc == NULL)
2019 return -1;
2020
David Ahern8fb598e2013-09-28 13:13:00 -06002021 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002022 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002023 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002024 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002025
David Ahernbf2575c2013-10-08 21:26:53 -06002026 if (trace->summary)
2027 thread__update_stats(ttrace, id, sample);
2028
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03002029 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002030
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002031 if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) {
2032 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2033 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002034 ++trace->stats.vfs_getname;
2035 }
2036
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002037 ttrace->exit_time = sample->time;
2038
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002039 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002040 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002041 if (trace__filter_duration(trace, duration))
2042 goto out;
2043 } else if (trace->duration_filter)
2044 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02002045
David Ahernfd2eaba2013-11-12 09:31:15 -07002046 if (trace->summary_only)
2047 goto out;
2048
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002049 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002050
2051 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002052 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002053 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002054 fprintf(trace->output, " ... [");
2055 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2056 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002057 }
2058
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002059 if (sc->fmt == NULL) {
2060signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002061 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002062 } else if (ret < 0 && sc->fmt->errmsg) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00002063 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002064 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2065 *e = audit_errno_to_name(-ret);
2066
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002067 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002068 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002069 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03002070 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09002071 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002072 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03002073 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002074
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002075 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002076out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002077 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002078 err = 0;
2079out_put:
2080 thread__put(thread);
2081 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03002082}
2083
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002084static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002085 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002086 struct perf_sample *sample)
2087{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002088 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2089 struct thread_trace *ttrace;
2090 size_t filename_len, entry_str_len, to_move;
2091 ssize_t remaining_space;
2092 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002093 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002094
2095 if (!thread)
2096 goto out;
2097
2098 ttrace = thread__priv(thread);
2099 if (!ttrace)
2100 goto out;
2101
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03002102 filename_len = strlen(filename);
2103
2104 if (ttrace->filename.namelen < filename_len) {
2105 char *f = realloc(ttrace->filename.name, filename_len + 1);
2106
2107 if (f == NULL)
2108 goto out;
2109
2110 ttrace->filename.namelen = filename_len;
2111 ttrace->filename.name = f;
2112 }
2113
2114 strcpy(ttrace->filename.name, filename);
2115 ttrace->filename.pending_open = true;
2116
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002117 if (!ttrace->filename.ptr)
2118 goto out;
2119
2120 entry_str_len = strlen(ttrace->entry_str);
2121 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2122 if (remaining_space <= 0)
2123 goto out;
2124
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03002125 if (filename_len > (size_t)remaining_space) {
2126 filename += filename_len - remaining_space;
2127 filename_len = remaining_space;
2128 }
2129
2130 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2131 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2132 memmove(pos + filename_len, pos, to_move);
2133 memcpy(pos, filename, filename_len);
2134
2135 ttrace->filename.ptr = 0;
2136 ttrace->filename.entry_str_pos = 0;
2137out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002138 return 0;
2139}
2140
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002141static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002142 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002143 struct perf_sample *sample)
2144{
2145 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2146 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06002147 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03002148 sample->pid,
2149 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002150 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002151
2152 if (ttrace == NULL)
2153 goto out_dump;
2154
2155 ttrace->runtime_ms += runtime_ms;
2156 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002157 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002158 return 0;
2159
2160out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002161 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002162 evsel->name,
2163 perf_evsel__strval(evsel, sample, "comm"),
2164 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2165 runtime,
2166 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002167 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002168 return 0;
2169}
2170
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002171static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2172 union perf_event *event __maybe_unused,
2173 struct perf_sample *sample)
2174{
2175 trace__printf_interrupted_entry(trace, sample);
2176 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002177
2178 if (trace->trace_syscalls)
2179 fprintf(trace->output, "( ): ");
2180
2181 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002182
2183 if (evsel->tp_format) {
2184 event_format__fprintf(evsel->tp_format, sample->cpu,
2185 sample->raw_data, sample->raw_size,
2186 trace->output);
2187 }
2188
2189 fprintf(trace->output, ")\n");
2190 return 0;
2191}
2192
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002193static void print_location(FILE *f, struct perf_sample *sample,
2194 struct addr_location *al,
2195 bool print_dso, bool print_sym)
2196{
2197
2198 if ((verbose || print_dso) && al->map)
2199 fprintf(f, "%s@", al->map->dso->long_name);
2200
2201 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002202 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002203 al->addr - al->sym->start);
2204 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002205 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002206 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002207 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002208}
2209
2210static int trace__pgfault(struct trace *trace,
2211 struct perf_evsel *evsel,
2212 union perf_event *event,
2213 struct perf_sample *sample)
2214{
2215 struct thread *thread;
2216 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2217 struct addr_location al;
2218 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002219 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002220 int err = -1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002221
2222 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002223 ttrace = thread__trace(thread, trace->output);
2224 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002225 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002226
2227 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2228 ttrace->pfmaj++;
2229 else
2230 ttrace->pfmin++;
2231
2232 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002233 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002234
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002235 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002236 sample->ip, &al);
2237
2238 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2239
2240 fprintf(trace->output, "%sfault [",
2241 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2242 "maj" : "min");
2243
2244 print_location(trace->output, sample, &al, false, true);
2245
2246 fprintf(trace->output, "] => ");
2247
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002248 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002249 sample->addr, &al);
2250
2251 if (!al.map) {
Arnaldo Carvalho de Melobb871a92014-10-23 12:50:25 -03002252 thread__find_addr_location(thread, cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002253 MAP__FUNCTION, sample->addr, &al);
2254
2255 if (al.map)
2256 map_type = 'x';
2257 else
2258 map_type = '?';
2259 }
2260
2261 print_location(trace->output, sample, &al, true, false);
2262
2263 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002264out:
2265 err = 0;
2266out_put:
2267 thread__put(thread);
2268 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002269}
2270
David Ahernbdc89662013-08-28 22:29:53 -06002271static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2272{
2273 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2274 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2275 return false;
2276
2277 if (trace->pid_list || trace->tid_list)
2278 return true;
2279
2280 return false;
2281}
2282
David Ahern6810fc92013-08-28 22:29:52 -06002283static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002284 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002285 struct perf_sample *sample,
2286 struct perf_evsel *evsel,
2287 struct machine *machine __maybe_unused)
2288{
2289 struct trace *trace = container_of(tool, struct trace, tool);
2290 int err = 0;
2291
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002292 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002293
David Ahernbdc89662013-08-28 22:29:53 -06002294 if (skip_sample(trace, sample))
2295 return 0;
2296
David Ahern4bb09192013-09-04 12:37:43 -06002297 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06002298 trace->base_time = sample->time;
2299
David Ahern31605652013-12-04 19:41:41 -07002300 if (handler) {
2301 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002302 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002303 }
David Ahern6810fc92013-08-28 22:29:52 -06002304
2305 return err;
2306}
2307
David Ahernbdc89662013-08-28 22:29:53 -06002308static int parse_target_str(struct trace *trace)
2309{
2310 if (trace->opts.target.pid) {
2311 trace->pid_list = intlist__new(trace->opts.target.pid);
2312 if (trace->pid_list == NULL) {
2313 pr_err("Error parsing process id string\n");
2314 return -EINVAL;
2315 }
2316 }
2317
2318 if (trace->opts.target.tid) {
2319 trace->tid_list = intlist__new(trace->opts.target.tid);
2320 if (trace->tid_list == NULL) {
2321 pr_err("Error parsing thread id string\n");
2322 return -EINVAL;
2323 }
2324 }
2325
2326 return 0;
2327}
2328
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002329static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002330{
2331 unsigned int rec_argc, i, j;
2332 const char **rec_argv;
2333 const char * const record_args[] = {
2334 "record",
2335 "-R",
2336 "-m", "1024",
2337 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002338 };
2339
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002340 const char * const sc_args[] = { "-e", };
2341 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2342 const char * const majpf_args[] = { "-e", "major-faults" };
2343 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2344 const char * const minpf_args[] = { "-e", "minor-faults" };
2345 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2346
David Ahern9aca7f12013-12-04 19:41:39 -07002347 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002348 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2349 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002350 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2351
2352 if (rec_argv == NULL)
2353 return -ENOMEM;
2354
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002355 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002356 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002357 rec_argv[j++] = record_args[i];
2358
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002359 if (trace->trace_syscalls) {
2360 for (i = 0; i < sc_args_nr; i++)
2361 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002362
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002363 /* event string may be different for older kernels - e.g., RHEL6 */
2364 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2365 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2366 else if (is_valid_tracepoint("syscalls:sys_enter"))
2367 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2368 else {
2369 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2370 return -1;
2371 }
David Ahern9aca7f12013-12-04 19:41:39 -07002372 }
David Ahern9aca7f12013-12-04 19:41:39 -07002373
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002374 if (trace->trace_pgfaults & TRACE_PFMAJ)
2375 for (i = 0; i < majpf_args_nr; i++)
2376 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002377
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002378 if (trace->trace_pgfaults & TRACE_PFMIN)
2379 for (i = 0; i < minpf_args_nr; i++)
2380 rec_argv[j++] = minpf_args[i];
2381
2382 for (i = 0; i < (unsigned int)argc; i++)
2383 rec_argv[j++] = argv[i];
2384
2385 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002386}
2387
David Ahernbf2575c2013-10-08 21:26:53 -06002388static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2389
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002390static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002391{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002392 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002393 if (evsel == NULL)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002394 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002395
2396 if (perf_evsel__field(evsel, "pathname") == NULL) {
2397 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002398 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002399 }
2400
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002401 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002402 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002403 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002404}
2405
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002406static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2407 u64 config)
2408{
2409 struct perf_evsel *evsel;
2410 struct perf_event_attr attr = {
2411 .type = PERF_TYPE_SOFTWARE,
2412 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002413 };
2414
2415 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002416 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002417
2418 event_attr_init(&attr);
2419
2420 evsel = perf_evsel__new(&attr);
2421 if (!evsel)
2422 return -ENOMEM;
2423
2424 evsel->handler = trace__pgfault;
2425 perf_evlist__add(evlist, evsel);
2426
2427 return 0;
2428}
2429
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002430static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2431{
2432 const u32 type = event->header.type;
2433 struct perf_evsel *evsel;
2434
2435 if (!trace->full_time && trace->base_time == 0)
2436 trace->base_time = sample->time;
2437
2438 if (type != PERF_RECORD_SAMPLE) {
2439 trace__process_event(trace, trace->host, event, sample);
2440 return;
2441 }
2442
2443 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2444 if (evsel == NULL) {
2445 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2446 return;
2447 }
2448
2449 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2450 sample->raw_data == NULL) {
2451 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2452 perf_evsel__name(evsel), sample->tid,
2453 sample->cpu, sample->raw_size);
2454 } else {
2455 tracepoint_handler handler = evsel->handler;
2456 handler(trace, evsel, event, sample);
2457 }
2458}
2459
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002460static int trace__add_syscall_newtp(struct trace *trace)
2461{
2462 int ret = -1;
2463 struct perf_evlist *evlist = trace->evlist;
2464 struct perf_evsel *sys_enter, *sys_exit;
2465
2466 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2467 if (sys_enter == NULL)
2468 goto out;
2469
2470 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2471 goto out_delete_sys_enter;
2472
2473 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2474 if (sys_exit == NULL)
2475 goto out_delete_sys_enter;
2476
2477 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2478 goto out_delete_sys_exit;
2479
2480 perf_evlist__add(evlist, sys_enter);
2481 perf_evlist__add(evlist, sys_exit);
2482
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002483 trace->syscalls.events.sys_enter = sys_enter;
2484 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002485
2486 ret = 0;
2487out:
2488 return ret;
2489
2490out_delete_sys_exit:
2491 perf_evsel__delete_priv(sys_exit);
2492out_delete_sys_enter:
2493 perf_evsel__delete_priv(sys_enter);
2494 goto out;
2495}
2496
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002497static int trace__set_ev_qualifier_filter(struct trace *trace)
2498{
2499 int err = -1;
2500 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2501 trace->ev_qualifier_ids.nr,
2502 trace->ev_qualifier_ids.entries);
2503
2504 if (filter == NULL)
2505 goto out_enomem;
2506
2507 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2508 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2509
2510 free(filter);
2511out:
2512 return err;
2513out_enomem:
2514 errno = ENOMEM;
2515 goto out;
2516}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002517
Namhyung Kimf15eb532012-10-05 14:02:16 +09002518static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002519{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002520 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002521 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002522 int err = -1, i;
2523 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002524 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002525 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002526
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002527 trace->live = true;
2528
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002529 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002530 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002531
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002532 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002533 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002534
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002535 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002536 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002537 goto out_error_mem;
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002538 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002539
2540 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2541 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002542 goto out_error_mem;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002543
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002544 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002545 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2546 trace__sched_stat_runtime))
2547 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002548
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002549 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2550 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002551 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002552 goto out_delete_evlist;
2553 }
2554
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002555 err = trace__symbols_init(trace, evlist);
2556 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002557 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002558 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002559 }
2560
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03002561 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002562
Namhyung Kimf15eb532012-10-05 14:02:16 +09002563 signal(SIGCHLD, sig_handler);
2564 signal(SIGINT, sig_handler);
2565
2566 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002567 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002568 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002569 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002570 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002571 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002572 }
2573 }
2574
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002575 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002576 if (err < 0)
2577 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002578
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002579 /*
2580 * Better not use !target__has_task() here because we need to cover the
2581 * case where no threads were specified in the command line, but a
2582 * workload was, and in that case we will fill in the thread_map when
2583 * we fork the workload in perf_evlist__prepare_workload.
2584 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002585 if (trace->filter_pids.nr > 0)
2586 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002587 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002588 err = perf_evlist__set_filter_pid(evlist, getpid());
2589
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002590 if (err < 0)
2591 goto out_error_mem;
2592
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002593 if (trace->ev_qualifier_ids.nr > 0) {
2594 err = trace__set_ev_qualifier_filter(trace);
2595 if (err < 0)
2596 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002597
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002598 pr_debug("event qualifier tracepoint filter: %s\n",
2599 trace->syscalls.events.sys_exit->filter);
2600 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002601
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002602 err = perf_evlist__apply_filters(evlist, &evsel);
2603 if (err < 0)
2604 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002605
Jiri Olsaf8850372013-11-28 17:57:22 +01002606 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002607 if (err < 0)
2608 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002609
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002610 if (!target__none(&trace->opts.target))
2611 perf_evlist__enable(evlist);
2612
Namhyung Kimf15eb532012-10-05 14:02:16 +09002613 if (forks)
2614 perf_evlist__start_workload(evlist);
2615
Jiri Olsae13798c2015-06-23 00:36:02 +02002616 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002617 evlist->threads->nr > 1 ||
2618 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002619again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002620 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002621
2622 for (i = 0; i < evlist->nr_mmaps; i++) {
2623 union perf_event *event;
2624
2625 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002626 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002627
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002628 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002629
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002630 err = perf_evlist__parse_sample(evlist, event, &sample);
2631 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002632 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002633 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002634 }
2635
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002636 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002637next_event:
2638 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002639
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002640 if (interrupted)
2641 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002642
2643 if (done && !draining) {
2644 perf_evlist__disable(evlist);
2645 draining = true;
2646 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002647 }
2648 }
2649
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002650 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002651 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002652
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002653 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2654 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2655 draining = true;
2656
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002657 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002658 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002659 } else {
2660 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002661 }
2662
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002663out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002664 thread__zput(trace->current);
2665
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002666 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002667
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002668 if (!err) {
2669 if (trace->summary)
2670 trace__fprintf_thread_summary(trace, trace->output);
2671
2672 if (trace->show_tool_stats) {
2673 fprintf(trace->output, "Stats:\n "
2674 " vfs_getname : %" PRIu64 "\n"
2675 " proc_getname: %" PRIu64 "\n",
2676 trace->stats.vfs_getname,
2677 trace->stats.proc_getname);
2678 }
2679 }
David Ahernbf2575c2013-10-08 21:26:53 -06002680
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002681out_delete_evlist:
2682 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002683 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002684 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002685 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002686{
2687 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002688
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002689out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002690 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002691 goto out_error;
2692
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002693out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002694 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002695 goto out_error;
2696
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002697out_error_mmap:
2698 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2699 goto out_error;
2700
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002701out_error_open:
2702 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2703
2704out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002705 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302706 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002707
2708out_error_apply_filters:
2709 fprintf(trace->output,
2710 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2711 evsel->filter, perf_evsel__name(evsel), errno,
2712 strerror_r(errno, errbuf, sizeof(errbuf)));
2713 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002714}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002715out_error_mem:
2716 fprintf(trace->output, "Not enough memory to run!\n");
2717 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002718
2719out_errno:
2720 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2721 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002722}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002723
David Ahern6810fc92013-08-28 22:29:52 -06002724static int trace__replay(struct trace *trace)
2725{
2726 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002727 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002728 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002729 struct perf_data_file file = {
2730 .path = input_name,
2731 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002732 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002733 };
David Ahern6810fc92013-08-28 22:29:52 -06002734 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002735 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002736 int err = -1;
2737
2738 trace->tool.sample = trace__process_sample;
2739 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002740 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002741 trace->tool.comm = perf_event__process_comm;
2742 trace->tool.exit = perf_event__process_exit;
2743 trace->tool.fork = perf_event__process_fork;
2744 trace->tool.attr = perf_event__process_attr;
2745 trace->tool.tracing_data = perf_event__process_tracing_data;
2746 trace->tool.build_id = perf_event__process_build_id;
2747
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002748 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002749 trace->tool.ordering_requires_timestamps = true;
2750
2751 /* add tid to output */
2752 trace->multiple_threads = true;
2753
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002754 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002755 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002756 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002757
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002758 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002759 goto out;
2760
David Ahern8fb598e2013-09-28 13:13:00 -06002761 trace->host = &session->machines.host;
2762
David Ahern6810fc92013-08-28 22:29:52 -06002763 err = perf_session__set_tracepoints_handlers(session, handlers);
2764 if (err)
2765 goto out;
2766
Namhyung Kim003824e2013-11-12 15:25:00 +09002767 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2768 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002769 /* older kernels have syscalls tp versus raw_syscalls */
2770 if (evsel == NULL)
2771 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2772 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002773
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002774 if (evsel &&
2775 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2776 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002777 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2778 goto out;
2779 }
2780
2781 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2782 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002783 if (evsel == NULL)
2784 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2785 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002786 if (evsel &&
2787 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2788 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002789 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002790 goto out;
2791 }
2792
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002793 evlist__for_each(session->evlist, evsel) {
2794 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2795 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2796 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2797 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2798 evsel->handler = trace__pgfault;
2799 }
2800
David Ahernbdc89662013-08-28 22:29:53 -06002801 err = parse_target_str(trace);
2802 if (err != 0)
2803 goto out;
2804
David Ahern6810fc92013-08-28 22:29:52 -06002805 setup_pager();
2806
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002807 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002808 if (err)
2809 pr_err("Failed to process events, error %d", err);
2810
David Ahernbf2575c2013-10-08 21:26:53 -06002811 else if (trace->summary)
2812 trace__fprintf_thread_summary(trace, trace->output);
2813
David Ahern6810fc92013-08-28 22:29:52 -06002814out:
2815 perf_session__delete(session);
2816
2817 return err;
2818}
2819
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002820static size_t trace__fprintf_threads_header(FILE *fp)
2821{
2822 size_t printed;
2823
Pekka Enberg99ff7152013-11-12 16:42:14 +02002824 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002825
2826 return printed;
2827}
2828
2829static size_t thread__dump_stats(struct thread_trace *ttrace,
2830 struct trace *trace, FILE *fp)
2831{
2832 struct stats *stats;
2833 size_t printed = 0;
2834 struct syscall *sc;
2835 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2836
2837 if (inode == NULL)
2838 return 0;
2839
2840 printed += fprintf(fp, "\n");
2841
Milian Wolff834fd462015-08-06 11:24:29 +02002842 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2843 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2844 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002845
David Ahernbf2575c2013-10-08 21:26:53 -06002846 /* each int_node is a syscall */
2847 while (inode) {
2848 stats = inode->priv;
2849 if (stats) {
2850 double min = (double)(stats->min) / NSEC_PER_MSEC;
2851 double max = (double)(stats->max) / NSEC_PER_MSEC;
2852 double avg = avg_stats(stats);
2853 double pct;
2854 u64 n = (u64) stats->n;
2855
2856 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2857 avg /= NSEC_PER_MSEC;
2858
2859 sc = &trace->syscalls.table[inode->i];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002860 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002861 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2862 n, avg * n, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002863 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002864 }
2865
2866 inode = intlist__next(inode);
2867 }
2868
2869 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002870
2871 return printed;
2872}
2873
David Ahern896cbb52013-09-28 13:12:59 -06002874/* struct used to pass data to per-thread function */
2875struct summary_data {
2876 FILE *fp;
2877 struct trace *trace;
2878 size_t printed;
2879};
2880
2881static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2882{
2883 struct summary_data *data = priv;
2884 FILE *fp = data->fp;
2885 size_t printed = data->printed;
2886 struct trace *trace = data->trace;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002887 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002888 double ratio;
2889
2890 if (ttrace == NULL)
2891 return 0;
2892
2893 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2894
Pekka Enberg15e65c62013-11-14 18:43:30 +02002895 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002896 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002897 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002898 if (ttrace->pfmaj)
2899 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2900 if (ttrace->pfmin)
2901 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002902 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
David Ahernbf2575c2013-10-08 21:26:53 -06002903 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002904
2905 data->printed += printed;
2906
2907 return 0;
2908}
2909
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002910static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2911{
David Ahern896cbb52013-09-28 13:12:59 -06002912 struct summary_data data = {
2913 .fp = fp,
2914 .trace = trace
2915 };
2916 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002917
David Ahern896cbb52013-09-28 13:12:59 -06002918 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002919
David Ahern896cbb52013-09-28 13:12:59 -06002920 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002921}
2922
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002923static int trace__set_duration(const struct option *opt, const char *str,
2924 int unset __maybe_unused)
2925{
2926 struct trace *trace = opt->value;
2927
2928 trace->duration_filter = atof(str);
2929 return 0;
2930}
2931
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002932static int trace__set_filter_pids(const struct option *opt, const char *str,
2933 int unset __maybe_unused)
2934{
2935 int ret = -1;
2936 size_t i;
2937 struct trace *trace = opt->value;
2938 /*
2939 * FIXME: introduce a intarray class, plain parse csv and create a
2940 * { int nr, int entries[] } struct...
2941 */
2942 struct intlist *list = intlist__new(str);
2943
2944 if (list == NULL)
2945 return -1;
2946
2947 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2948 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2949
2950 if (trace->filter_pids.entries == NULL)
2951 goto out;
2952
2953 trace->filter_pids.entries[0] = getpid();
2954
2955 for (i = 1; i < trace->filter_pids.nr; ++i)
2956 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2957
2958 intlist__delete(list);
2959 ret = 0;
2960out:
2961 return ret;
2962}
2963
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002964static int trace__open_output(struct trace *trace, const char *filename)
2965{
2966 struct stat st;
2967
2968 if (!stat(filename, &st) && st.st_size) {
2969 char oldname[PATH_MAX];
2970
2971 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2972 unlink(oldname);
2973 rename(filename, oldname);
2974 }
2975
2976 trace->output = fopen(filename, "w");
2977
2978 return trace->output == NULL ? -errno : 0;
2979}
2980
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002981static int parse_pagefaults(const struct option *opt, const char *str,
2982 int unset __maybe_unused)
2983{
2984 int *trace_pgfaults = opt->value;
2985
2986 if (strcmp(str, "all") == 0)
2987 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2988 else if (strcmp(str, "maj") == 0)
2989 *trace_pgfaults |= TRACE_PFMAJ;
2990 else if (strcmp(str, "min") == 0)
2991 *trace_pgfaults |= TRACE_PFMIN;
2992 else
2993 return -1;
2994
2995 return 0;
2996}
2997
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002998static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2999{
3000 struct perf_evsel *evsel;
3001
3002 evlist__for_each(evlist, evsel)
3003 evsel->handler = handler;
3004}
3005
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003006int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
3007{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003008 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003009 "perf trace [<options>] [<command>]",
3010 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003011 "perf trace record [<options>] [<command>]",
3012 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003013 NULL
3014 };
3015 struct trace trace = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003016 .audit = {
3017 .machine = audit_detect_machine(),
3018 .open_id = audit_name_to_syscall("open", trace.audit.machine),
3019 },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003020 .syscalls = {
3021 . max = -1,
3022 },
3023 .opts = {
3024 .target = {
3025 .uid = UINT_MAX,
3026 .uses_mmap = true,
3027 },
3028 .user_freq = UINT_MAX,
3029 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003030 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003031 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003032 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003033 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003034 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003035 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003036 .trace_syscalls = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003037 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003038 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003039 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003040 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003041 OPT_CALLBACK(0, "event", &trace.evlist, "event",
3042 "event selector. use 'perf list' to list available events",
3043 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003044 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3045 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003046 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03003047 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003048 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003049 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003050 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3051 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003052 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003053 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003054 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3055 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003056 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003057 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003058 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003059 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003060 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003061 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003062 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3063 "number of mmap data pages",
3064 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003065 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003066 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003067 OPT_CALLBACK(0, "duration", &trace, "float",
3068 "show only events with duration > N.M ms",
3069 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003070 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003071 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003072 OPT_BOOLEAN('T', "time", &trace.full_time,
3073 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003074 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3075 "Show only syscall summary with statistics"),
3076 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3077 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003078 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3079 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003080 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003081 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003082 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3083 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003084 OPT_END()
3085 };
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003086 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003087 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003088 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003089
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003090 signal(SIGSEGV, sighandler_dump_stack);
3091 signal(SIGFPE, sighandler_dump_stack);
3092
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003093 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003094
3095 if (trace.evlist == NULL) {
3096 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003097 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003098 goto out;
3099 }
3100
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003101 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3102 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003103
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003104 if (trace.trace_pgfaults) {
3105 trace.opts.sample_address = true;
3106 trace.opts.sample_time = true;
3107 }
3108
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003109 if (trace.evlist->nr_entries > 0)
3110 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3111
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003112 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3113 return trace__record(&trace, argc-1, &argv[1]);
3114
3115 /* summary_only implies summary option, but don't overwrite summary if set */
3116 if (trace.summary_only)
3117 trace.summary = trace.summary_only;
3118
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003119 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3120 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003121 pr_err("Please specify something to trace.\n");
3122 return -1;
3123 }
3124
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003125 if (output_name != NULL) {
3126 err = trace__open_output(&trace, output_name);
3127 if (err < 0) {
3128 perror("failed to create output file");
3129 goto out;
3130 }
3131 }
3132
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003133 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003134 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003135 struct strlist_config slist_config = {
3136 .dirname = system_path(STRACE_GROUPS_DIR),
3137 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03003138
3139 trace.not_ev_qualifier = *s == '!';
3140 if (trace.not_ev_qualifier)
3141 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03003142 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003143 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003144 fputs("Not enough memory to parse event qualifier",
3145 trace.output);
3146 err = -ENOMEM;
3147 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003148 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03003149
3150 err = trace__validate_ev_qualifier(&trace);
3151 if (err)
3152 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03003153 }
3154
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003155 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003156 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003157 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003158 fprintf(trace.output, "%s", bf);
3159 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003160 }
3161
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003162 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003163 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003164 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003165 fprintf(trace.output, "%s", bf);
3166 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003167 }
3168
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003169 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003170 trace.opts.target.system_wide = true;
3171
David Ahern6810fc92013-08-28 22:29:52 -06003172 if (input_name)
3173 err = trace__replay(&trace);
3174 else
3175 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003176
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003177out_close:
3178 if (output_name != NULL)
3179 fclose(trace.output);
3180out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003181 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003182}