blob: e065c4a12f5855b34c4367f18f626b5378a6bbda [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030034#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010035#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070036#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000037#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020038#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030039#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030040#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030042#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030043
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030044#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030045#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030046#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030047#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030048#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020049#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030050#include <linux/filter.h>
51#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030052#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030053#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030054#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030055#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030056
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030057#include "sane_ctype.h"
58
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030059#ifndef O_CLOEXEC
60# define O_CLOEXEC 02000000
61#endif
62
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030063struct trace {
64 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030065 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030066 struct {
67 int max;
68 struct syscall *table;
69 struct {
70 struct perf_evsel *sys_enter,
71 *sys_exit;
72 } events;
73 } syscalls;
74 struct record_opts opts;
75 struct perf_evlist *evlist;
76 struct machine *host;
77 struct thread *current;
78 u64 base_time;
79 FILE *output;
80 unsigned long nr_events;
81 struct strlist *ev_qualifier;
82 struct {
83 size_t nr;
84 int *entries;
85 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030086 struct {
87 size_t nr;
88 pid_t *entries;
89 } filter_pids;
90 double duration_filter;
91 double runtime_ms;
92 struct {
93 u64 vfs_getname,
94 proc_getname;
95 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030096 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030097 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030098 bool not_ev_qualifier;
99 bool live;
100 bool full_time;
101 bool sched;
102 bool multiple_threads;
103 bool summary;
104 bool summary_only;
105 bool show_comm;
106 bool show_tool_stats;
107 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300108 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300109 bool force;
110 bool vfs_getname;
111 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300112 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300113};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300114
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300115struct tp_field {
116 int offset;
117 union {
118 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
119 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
120 };
121};
122
123#define TP_UINT_FIELD(bits) \
124static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
125{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500126 u##bits value; \
127 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
128 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300129}
130
131TP_UINT_FIELD(8);
132TP_UINT_FIELD(16);
133TP_UINT_FIELD(32);
134TP_UINT_FIELD(64);
135
136#define TP_UINT_FIELD__SWAPPED(bits) \
137static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
138{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500139 u##bits value; \
140 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300141 return bswap_##bits(value);\
142}
143
144TP_UINT_FIELD__SWAPPED(16);
145TP_UINT_FIELD__SWAPPED(32);
146TP_UINT_FIELD__SWAPPED(64);
147
148static int tp_field__init_uint(struct tp_field *field,
149 struct format_field *format_field,
150 bool needs_swap)
151{
152 field->offset = format_field->offset;
153
154 switch (format_field->size) {
155 case 1:
156 field->integer = tp_field__u8;
157 break;
158 case 2:
159 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
160 break;
161 case 4:
162 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
163 break;
164 case 8:
165 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
166 break;
167 default:
168 return -1;
169 }
170
171 return 0;
172}
173
174static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
175{
176 return sample->raw_data + field->offset;
177}
178
179static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
180{
181 field->offset = format_field->offset;
182 field->pointer = tp_field__ptr;
183 return 0;
184}
185
186struct syscall_tp {
187 struct tp_field id;
188 union {
189 struct tp_field args, ret;
190 };
191};
192
193static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
194 struct tp_field *field,
195 const char *name)
196{
197 struct format_field *format_field = perf_evsel__field(evsel, name);
198
199 if (format_field == NULL)
200 return -1;
201
202 return tp_field__init_uint(field, format_field, evsel->needs_swap);
203}
204
205#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
206 ({ struct syscall_tp *sc = evsel->priv;\
207 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
208
209static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
210 struct tp_field *field,
211 const char *name)
212{
213 struct format_field *format_field = perf_evsel__field(evsel, name);
214
215 if (format_field == NULL)
216 return -1;
217
218 return tp_field__init_ptr(field, format_field);
219}
220
221#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
222 ({ struct syscall_tp *sc = evsel->priv;\
223 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
224
225static void perf_evsel__delete_priv(struct perf_evsel *evsel)
226{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300227 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300228 perf_evsel__delete(evsel);
229}
230
Namhyung Kim96695d42013-11-12 08:51:45 -0300231static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
232{
233 evsel->priv = malloc(sizeof(struct syscall_tp));
234 if (evsel->priv != NULL) {
235 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
236 goto out_delete;
237
238 evsel->handler = handler;
239 return 0;
240 }
241
242 return -ENOMEM;
243
244out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300245 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300246 return -ENOENT;
247}
248
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300249static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300250{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300251 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300252
David Ahern9aca7f12013-12-04 19:41:39 -0700253 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200254 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700255 evsel = perf_evsel__newtp("syscalls", direction);
256
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200257 if (IS_ERR(evsel))
258 return NULL;
259
260 if (perf_evsel__init_syscall_tp(evsel, handler))
261 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300262
263 return evsel;
264
265out_delete:
266 perf_evsel__delete_priv(evsel);
267 return NULL;
268}
269
270#define perf_evsel__sc_tp_uint(evsel, name, sample) \
271 ({ struct syscall_tp *fields = evsel->priv; \
272 fields->name.integer(&fields->name, sample); })
273
274#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
275 ({ struct syscall_tp *fields = evsel->priv; \
276 fields->name.pointer(&fields->name, sample); })
277
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300278struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300279 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280 int nr_entries;
281 const char **entries;
282};
283
284#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
285 .nr_entries = ARRAY_SIZE(array), \
286 .entries = array, \
287}
288
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300289#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
290 .offset = off, \
291 .nr_entries = ARRAY_SIZE(array), \
292 .entries = array, \
293}
294
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300295static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
296 const char *intfmt,
297 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300298{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300300 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301
302 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300304
305 return scnprintf(bf, size, "%s", sa->entries[idx]);
306}
307
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300308static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
309 struct syscall_arg *arg)
310{
311 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
312}
313
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300314#define SCA_STRARRAY syscall_arg__scnprintf_strarray
315
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300316#if defined(__i386__) || defined(__x86_64__)
317/*
318 * FIXME: Make this available to all arches as soon as the ioctl beautifier
319 * gets rewritten to support all arches.
320 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300321static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
322 struct syscall_arg *arg)
323{
324 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
325}
326
327#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300328#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300329
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300330static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
331 struct syscall_arg *arg);
332
333#define SCA_FD syscall_arg__scnprintf_fd
334
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300335#ifndef AT_FDCWD
336#define AT_FDCWD -100
337#endif
338
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300339static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
340 struct syscall_arg *arg)
341{
342 int fd = arg->val;
343
344 if (fd == AT_FDCWD)
345 return scnprintf(bf, size, "CWD");
346
347 return syscall_arg__scnprintf_fd(bf, size, arg);
348}
349
350#define SCA_FDAT syscall_arg__scnprintf_fd_at
351
352static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
353 struct syscall_arg *arg);
354
355#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
356
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300357static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300358 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300359{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300360 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300361}
362
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300363#define SCA_HEX syscall_arg__scnprintf_hex
364
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300365static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
366 struct syscall_arg *arg)
367{
368 return scnprintf(bf, size, "%d", arg->val);
369}
370
371#define SCA_INT syscall_arg__scnprintf_int
372
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300373static const char *bpf_cmd[] = {
374 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
375 "MAP_GET_NEXT_KEY", "PROG_LOAD",
376};
377static DEFINE_STRARRAY(bpf_cmd);
378
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300379static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
380static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300381
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300382static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
383static DEFINE_STRARRAY(itimers);
384
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300385static const char *keyctl_options[] = {
386 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
387 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
388 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
389 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
390 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
391};
392static DEFINE_STRARRAY(keyctl_options);
393
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300394static const char *whences[] = { "SET", "CUR", "END",
395#ifdef SEEK_DATA
396"DATA",
397#endif
398#ifdef SEEK_HOLE
399"HOLE",
400#endif
401};
402static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300403
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300404static const char *fcntl_cmds[] = {
405 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
406 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
407 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
408 "F_GETOWNER_UIDS",
409};
410static DEFINE_STRARRAY(fcntl_cmds);
411
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300412static const char *rlimit_resources[] = {
413 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
414 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
415 "RTTIME",
416};
417static DEFINE_STRARRAY(rlimit_resources);
418
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300419static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
420static DEFINE_STRARRAY(sighow);
421
David Ahern4f8c1b72013-09-22 19:45:00 -0600422static const char *clockid[] = {
423 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300424 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
425 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600426};
427static DEFINE_STRARRAY(clockid);
428
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300429static const char *socket_families[] = {
430 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
431 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
432 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
433 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
434 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
435 "ALG", "NFC", "VSOCK",
436};
437static DEFINE_STRARRAY(socket_families);
438
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300439static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
440 struct syscall_arg *arg)
441{
442 size_t printed = 0;
443 int mode = arg->val;
444
445 if (mode == F_OK) /* 0 */
446 return scnprintf(bf, size, "F");
447#define P_MODE(n) \
448 if (mode & n##_OK) { \
449 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
450 mode &= ~n##_OK; \
451 }
452
453 P_MODE(R);
454 P_MODE(W);
455 P_MODE(X);
456#undef P_MODE
457
458 if (mode)
459 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
460
461 return printed;
462}
463
464#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
465
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300466static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
467 struct syscall_arg *arg);
468
469#define SCA_FILENAME syscall_arg__scnprintf_filename
470
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300471static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
472 struct syscall_arg *arg)
473{
474 int printed = 0, flags = arg->val;
475
476#define P_FLAG(n) \
477 if (flags & O_##n) { \
478 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
479 flags &= ~O_##n; \
480 }
481
482 P_FLAG(CLOEXEC);
483 P_FLAG(NONBLOCK);
484#undef P_FLAG
485
486 if (flags)
487 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
488
489 return printed;
490}
491
492#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
493
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300494#if defined(__i386__) || defined(__x86_64__)
495/*
496 * FIXME: Make this available to all arches.
497 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300498#define TCGETS 0x5401
499
500static const char *tioctls[] = {
501 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
502 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
503 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
504 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
505 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
506 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
507 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
508 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
509 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
510 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
511 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
512 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
513 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
514 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
515 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
516};
517
518static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300519#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300520
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300521#ifndef GRND_NONBLOCK
522#define GRND_NONBLOCK 0x0001
523#endif
524#ifndef GRND_RANDOM
525#define GRND_RANDOM 0x0002
526#endif
527
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300528static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
529 struct syscall_arg *arg)
530{
531 int printed = 0, flags = arg->val;
532
533#define P_FLAG(n) \
534 if (flags & GRND_##n) { \
535 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
536 flags &= ~GRND_##n; \
537 }
538
539 P_FLAG(RANDOM);
540 P_FLAG(NONBLOCK);
541#undef P_FLAG
542
543 if (flags)
544 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
545
546 return printed;
547}
548
549#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
550
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300551#define STRARRAY(arg, name, array) \
552 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
553 .arg_parm = { [arg] = &strarray__##array, }
554
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300555#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300556#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300557#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300558#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300559#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300560#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300561#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300562#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300563#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300564#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300565#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300566#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300567#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300568#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300569
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300570static struct syscall_fmt {
571 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300572 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300573 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300574 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300575 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300576 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300577 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300578 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300579} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300580 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300581 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300582 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300583 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300584 { .name = "brk", .hexret = true,
585 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300586 { .name = "chdir", .errmsg = true, },
587 { .name = "chmod", .errmsg = true, },
588 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600589 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300590 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300591 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300592 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300593 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300594 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300595 { .name = "dup", .errmsg = true, },
596 { .name = "dup2", .errmsg = true, },
597 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300598 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300599 { .name = "eventfd2", .errmsg = true,
600 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300601 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300602 { .name = "fadvise64", .errmsg = true, },
603 { .name = "fallocate", .errmsg = true, },
604 { .name = "fchdir", .errmsg = true, },
605 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300606 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300607 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300608 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300609 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300610 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300611 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300612 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300613 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300614 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300615 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300616 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
617 { .name = "fsetxattr", .errmsg = true, },
618 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300619 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300620 { .name = "fstatfs", .errmsg = true, },
621 { .name = "fsync", .errmsg = true, },
622 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300623 { .name = "futex", .errmsg = true,
624 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300625 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300626 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300627 { .name = "getdents", .errmsg = true, },
628 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300629 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300630 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300631 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300632 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300633 { .name = "getrandom", .errmsg = true,
634 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300635 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300636 { .name = "getxattr", .errmsg = true, },
637 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300638 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300639 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300640#if defined(__i386__) || defined(__x86_64__)
641/*
642 * FIXME: Make this available to all arches.
643 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300644 [1] = SCA_STRHEXARRAY, /* cmd */
645 [2] = SCA_HEX, /* arg */ },
646 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300647#else
648 [2] = SCA_HEX, /* arg */ }, },
649#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300650 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300651 { .name = "kill", .errmsg = true,
652 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300653 { .name = "lchown", .errmsg = true, },
654 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300655 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300656 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300657 { .name = "listxattr", .errmsg = true, },
658 { .name = "llistxattr", .errmsg = true, },
659 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300660 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300661 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300662 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300663 { .name = "lsetxattr", .errmsg = true, },
664 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
665 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300666 { .name = "madvise", .errmsg = true,
667 .arg_scnprintf = { [0] = SCA_HEX, /* start */
668 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300669 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300670 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300671 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
672 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300673 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300674 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300675 { .name = "mlock", .errmsg = true,
676 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
677 { .name = "mlockall", .errmsg = true,
678 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300679 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300680 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300681 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300682 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300683 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300684 .arg_scnprintf = { [0] = SCA_HEX, /* start */
685 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300686 { .name = "mq_unlink", .errmsg = true,
687 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300688 { .name = "mremap", .hexret = true,
689 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300690 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300691 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300692 { .name = "munlock", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300694 { .name = "munmap", .errmsg = true,
695 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300696 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300697 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300698 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300699 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300700 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300701 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300702 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300703 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
704 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300705 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300706 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
707 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300708 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300709 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300710 [3] = SCA_FD, /* group_fd */
711 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300712 { .name = "pipe2", .errmsg = true,
713 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300714 { .name = "poll", .errmsg = true, .timeout = true, },
715 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300716 { .name = "pread", .errmsg = true, .alias = "pread64", },
717 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300718 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300719 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
720 { .name = "pwritev", .errmsg = true, },
721 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300722 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300723 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300724 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300725 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300726 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300727 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300728 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300729 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300730 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300731 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300732 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300733 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300734 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300735 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300736 { .name = "rt_sigaction", .errmsg = true,
737 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300738 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300739 { .name = "rt_sigqueueinfo", .errmsg = true,
740 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
741 { .name = "rt_tgsigqueueinfo", .errmsg = true,
742 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300743 { .name = "sched_getattr", .errmsg = true, },
744 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300745 { .name = "sched_setscheduler", .errmsg = true,
746 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300747 { .name = "seccomp", .errmsg = true,
748 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
749 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300750 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300751 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300752 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300753 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300754 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300755 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300756 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300757 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300758 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300759 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300760 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300761 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300762 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300763 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300764 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
765 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300766 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300767 { .name = "socketpair", .errmsg = true,
768 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
769 [1] = SCA_SK_TYPE, /* type */ },
770 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300771 { .name = "stat", .errmsg = true, .alias = "newstat", },
772 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300773 { .name = "statx", .errmsg = true,
774 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
775 [2] = SCA_STATX_FLAGS, /* flags */
776 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300777 { .name = "swapoff", .errmsg = true,
778 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
779 { .name = "swapon", .errmsg = true,
780 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300781 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300782 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300783 { .name = "tgkill", .errmsg = true,
784 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
785 { .name = "tkill", .errmsg = true,
786 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300787 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300788 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300789 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300790 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
791 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300792 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300793 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
794 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300795 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300796 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300797 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300798 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300799 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300800 { .name = "write", .errmsg = true, },
801 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300802};
803
804static int syscall_fmt__cmp(const void *name, const void *fmtp)
805{
806 const struct syscall_fmt *fmt = fmtp;
807 return strcmp(name, fmt->name);
808}
809
810static struct syscall_fmt *syscall_fmt__find(const char *name)
811{
812 const int nmemb = ARRAY_SIZE(syscall_fmts);
813 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
814}
815
816struct syscall {
817 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300818 int nr_args;
819 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300820 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300821 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300822 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300823 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300824 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300825};
826
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300827/*
828 * We need to have this 'calculated' boolean because in some cases we really
829 * don't know what is the duration of a syscall, for instance, when we start
830 * a session and some threads are waiting for a syscall to finish, say 'poll',
831 * in which case all we can do is to print "( ? ) for duration and for the
832 * start timestamp.
833 */
834static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200835{
836 double duration = (double)t / NSEC_PER_MSEC;
837 size_t printed = fprintf(fp, "(");
838
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300839 if (!calculated)
840 printed += fprintf(fp, " ? ");
841 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200842 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
843 else if (duration >= 0.01)
844 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
845 else
846 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300847 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200848}
849
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300850/**
851 * filename.ptr: The filename char pointer that will be vfs_getname'd
852 * filename.entry_str_pos: Where to insert the string translated from
853 * filename.ptr by the vfs_getname tracepoint/kprobe.
854 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300855struct thread_trace {
856 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300857 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300858 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400859 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300860 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300861 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300862 struct {
863 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300864 short int entry_str_pos;
865 bool pending_open;
866 unsigned int namelen;
867 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300868 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300869 struct {
870 int max;
871 char **table;
872 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600873
874 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300875};
876
877static struct thread_trace *thread_trace__new(void)
878{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300879 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
880
881 if (ttrace)
882 ttrace->paths.max = -1;
883
David Ahernbf2575c2013-10-08 21:26:53 -0600884 ttrace->syscall_stats = intlist__new(NULL);
885
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300886 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300887}
888
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300889static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300891 struct thread_trace *ttrace;
892
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300893 if (thread == NULL)
894 goto fail;
895
Namhyung Kim89dceb22014-10-06 09:46:03 +0900896 if (thread__priv(thread) == NULL)
897 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300898
Namhyung Kim89dceb22014-10-06 09:46:03 +0900899 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300900 goto fail;
901
Namhyung Kim89dceb22014-10-06 09:46:03 +0900902 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300903 ++ttrace->nr_events;
904
905 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300906fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300907 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300908 "WARNING: not enough memory, dropping samples!\n");
909 return NULL;
910}
911
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400912#define TRACE_PFMAJ (1 << 0)
913#define TRACE_PFMIN (1 << 1)
914
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300915static const size_t trace__entry_str_size = 2048;
916
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300917static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900919 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300920
921 if (fd > ttrace->paths.max) {
922 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
923
924 if (npath == NULL)
925 return -1;
926
927 if (ttrace->paths.max != -1) {
928 memset(npath + ttrace->paths.max + 1, 0,
929 (fd - ttrace->paths.max) * sizeof(char *));
930 } else {
931 memset(npath, 0, (fd + 1) * sizeof(char *));
932 }
933
934 ttrace->paths.table = npath;
935 ttrace->paths.max = fd;
936 }
937
938 ttrace->paths.table[fd] = strdup(pathname);
939
940 return ttrace->paths.table[fd] != NULL ? 0 : -1;
941}
942
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300943static int thread__read_fd_path(struct thread *thread, int fd)
944{
945 char linkname[PATH_MAX], pathname[PATH_MAX];
946 struct stat st;
947 int ret;
948
949 if (thread->pid_ == thread->tid) {
950 scnprintf(linkname, sizeof(linkname),
951 "/proc/%d/fd/%d", thread->pid_, fd);
952 } else {
953 scnprintf(linkname, sizeof(linkname),
954 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
955 }
956
957 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
958 return -1;
959
960 ret = readlink(linkname, pathname, sizeof(pathname));
961
962 if (ret < 0 || ret > st.st_size)
963 return -1;
964
965 pathname[ret] = '\0';
966 return trace__set_fd_pathname(thread, fd, pathname);
967}
968
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300969static const char *thread__fd_path(struct thread *thread, int fd,
970 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300971{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900972 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300973
974 if (ttrace == NULL)
975 return NULL;
976
977 if (fd < 0)
978 return NULL;
979
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300980 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300981 if (!trace->live)
982 return NULL;
983 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300984 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300985 return NULL;
986 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300987
988 return ttrace->paths.table[fd];
989}
990
991static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
992 struct syscall_arg *arg)
993{
994 int fd = arg->val;
995 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300996 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997
998 if (path)
999 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1000
1001 return printed;
1002}
1003
1004static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1005 struct syscall_arg *arg)
1006{
1007 int fd = arg->val;
1008 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001009 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001010
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001011 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1012 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001013
1014 return printed;
1015}
1016
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001017static void thread__set_filename_pos(struct thread *thread, const char *bf,
1018 unsigned long ptr)
1019{
1020 struct thread_trace *ttrace = thread__priv(thread);
1021
1022 ttrace->filename.ptr = ptr;
1023 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1024}
1025
1026static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1027 struct syscall_arg *arg)
1028{
1029 unsigned long ptr = arg->val;
1030
1031 if (!arg->trace->vfs_getname)
1032 return scnprintf(bf, size, "%#x", ptr);
1033
1034 thread__set_filename_pos(arg->thread, bf, ptr);
1035 return 0;
1036}
1037
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001038static bool trace__filter_duration(struct trace *trace, double t)
1039{
1040 return t < (trace->duration_filter * NSEC_PER_MSEC);
1041}
1042
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001043static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001044{
1045 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1046
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001047 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001048}
1049
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001050/*
1051 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1052 * using ttrace->entry_time for a thread that receives a sys_exit without
1053 * first having received a sys_enter ("poll" issued before tracing session
1054 * starts, lost sys_enter exit due to ring buffer overflow).
1055 */
1056static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1057{
1058 if (tstamp > 0)
1059 return __trace__fprintf_tstamp(trace, tstamp, fp);
1060
1061 return fprintf(fp, " ? ");
1062}
1063
Namhyung Kimf15eb532012-10-05 14:02:16 +09001064static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001065static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001066
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001067static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001068{
1069 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001070 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001071}
1072
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001073static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001074 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001075{
1076 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001077 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001078
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001079 if (trace->multiple_threads) {
1080 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001081 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001082 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001083 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084
1085 return printed;
1086}
1087
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001088static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001089 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001090{
1091 int ret = 0;
1092
1093 switch (event->header.type) {
1094 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001095 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001097 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001098 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001099 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001100 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101 break;
1102 }
1103
1104 return ret;
1105}
1106
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001107static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001108 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001109 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110 struct machine *machine)
1111{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001112 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001113 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001114}
1115
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001116static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1117{
1118 struct machine *machine = vmachine;
1119
1120 if (machine->kptr_restrict_warned)
1121 return NULL;
1122
1123 if (symbol_conf.kptr_restrict) {
1124 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1125 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1126 "Kernel samples will not be resolved.\n");
1127 machine->kptr_restrict_warned = true;
1128 return NULL;
1129 }
1130
1131 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1132}
1133
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001134static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1135{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001136 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137
1138 if (err)
1139 return err;
1140
David Ahern8fb598e2013-09-28 13:13:00 -06001141 trace->host = machine__new_host();
1142 if (trace->host == NULL)
1143 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001144
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001145 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001146 return -errno;
1147
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001148 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001149 evlist->threads, trace__tool_process, false,
1150 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001151 if (err)
1152 symbol__exit();
1153
1154 return err;
1155}
1156
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001157static int syscall__set_arg_fmts(struct syscall *sc)
1158{
1159 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001160 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001161
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001162 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001163 if (sc->arg_scnprintf == NULL)
1164 return -1;
1165
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001166 if (sc->fmt)
1167 sc->arg_parm = sc->fmt->arg_parm;
1168
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001169 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001170 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1171 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001172 else if (strcmp(field->type, "const char *") == 0 &&
1173 (strcmp(field->name, "filename") == 0 ||
1174 strcmp(field->name, "path") == 0 ||
1175 strcmp(field->name, "pathname") == 0))
1176 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001177 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001178 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001179 else if (strcmp(field->type, "pid_t") == 0)
1180 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001181 else if (strcmp(field->type, "umode_t") == 0)
1182 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001183 else if ((strcmp(field->type, "int") == 0 ||
1184 strcmp(field->type, "unsigned int") == 0 ||
1185 strcmp(field->type, "long") == 0) &&
1186 (len = strlen(field->name)) >= 2 &&
1187 strcmp(field->name + len - 2, "fd") == 0) {
1188 /*
1189 * /sys/kernel/tracing/events/syscalls/sys_enter*
1190 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1191 * 65 int
1192 * 23 unsigned int
1193 * 7 unsigned long
1194 */
1195 sc->arg_scnprintf[idx] = SCA_FD;
1196 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001197 ++idx;
1198 }
1199
1200 return 0;
1201}
1202
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001203static int trace__read_syscall_info(struct trace *trace, int id)
1204{
1205 char tp_name[128];
1206 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001207 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001208
1209 if (name == NULL)
1210 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001211
1212 if (id > trace->syscalls.max) {
1213 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1214
1215 if (nsyscalls == NULL)
1216 return -1;
1217
1218 if (trace->syscalls.max != -1) {
1219 memset(nsyscalls + trace->syscalls.max + 1, 0,
1220 (id - trace->syscalls.max) * sizeof(*sc));
1221 } else {
1222 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1223 }
1224
1225 trace->syscalls.table = nsyscalls;
1226 trace->syscalls.max = id;
1227 }
1228
1229 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001230 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001231
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001232 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001233
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001234 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001235 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001236
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001237 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001238 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001239 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001240 }
1241
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001242 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001243 return -1;
1244
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001245 sc->args = sc->tp_format->format.fields;
1246 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001247 /*
1248 * We need to check and discard the first variable '__syscall_nr'
1249 * or 'nr' that mean the syscall number. It is needless here.
1250 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1251 */
1252 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001253 sc->args = sc->args->next;
1254 --sc->nr_args;
1255 }
1256
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001257 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1258
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001259 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001260}
1261
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001262static int trace__validate_ev_qualifier(struct trace *trace)
1263{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001264 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001265 struct str_node *pos;
1266
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001267 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1268 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1269 sizeof(trace->ev_qualifier_ids.entries[0]));
1270
1271 if (trace->ev_qualifier_ids.entries == NULL) {
1272 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1273 trace->output);
1274 err = -EINVAL;
1275 goto out;
1276 }
1277
1278 i = 0;
1279
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001280 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001281 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001282 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001283
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001284 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001285 if (err == 0) {
1286 fputs("Error:\tInvalid syscall ", trace->output);
1287 err = -EINVAL;
1288 } else {
1289 fputs(", ", trace->output);
1290 }
1291
1292 fputs(sc, trace->output);
1293 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001294
1295 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001296 }
1297
1298 if (err < 0) {
1299 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1300 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001301 zfree(&trace->ev_qualifier_ids.entries);
1302 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001303 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001304out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001305 return err;
1306}
1307
David Ahern55d43bc2015-02-19 15:00:22 -05001308/*
1309 * args is to be interpreted as a series of longs but we need to handle
1310 * 8-byte unaligned accesses. args points to raw_data within the event
1311 * and raw_data is guaranteed to be 8-byte unaligned because it is
1312 * preceded by raw_size which is a u32. So we need to copy args to a temp
1313 * variable to read it. Most notably this avoids extended load instructions
1314 * on unaligned addresses
1315 */
1316
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001317static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001318 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001319 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001320{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001322 unsigned char *p;
1323 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001324
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001325 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001326 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001327 u8 bit = 1;
1328 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329 .idx = 0,
1330 .mask = 0,
1331 .trace = trace,
1332 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001333 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001334
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001335 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001336 field = field->next, ++arg.idx, bit <<= 1) {
1337 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001338 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001339
1340 /* special care for unaligned accesses */
1341 p = args + sizeof(unsigned long) * arg.idx;
1342 memcpy(&val, p, sizeof(val));
1343
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001344 /*
1345 * Suppress this argument if its value is zero and
1346 * and we don't have a string associated in an
1347 * strarray for it.
1348 */
David Ahern55d43bc2015-02-19 15:00:22 -05001349 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001350 !(sc->arg_scnprintf &&
1351 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1352 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001353 continue;
1354
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001355 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001356 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001357 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001358 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001359 if (sc->arg_parm)
1360 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001361 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1362 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001363 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001364 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001365 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001366 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001367 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001368 } else if (IS_ERR(sc->tp_format)) {
1369 /*
1370 * If we managed to read the tracepoint /format file, then we
1371 * may end up not having any args, like with gettid(), so only
1372 * print the raw args when we didn't manage to read it.
1373 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001374 int i = 0;
1375
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001376 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001377 /* special care for unaligned accesses */
1378 p = args + sizeof(unsigned long) * i;
1379 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001380 printed += scnprintf(bf + printed, size - printed,
1381 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001382 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001383 ++i;
1384 }
1385 }
1386
1387 return printed;
1388}
1389
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001390typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001391 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001392 struct perf_sample *sample);
1393
1394static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001395 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001396{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001397
1398 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001399
1400 /*
1401 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1402 * before that, leaving at a higher verbosity level till that is
1403 * explained. Reproduced with plain ftrace with:
1404 *
1405 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1406 * grep "NR -1 " /t/trace_pipe
1407 *
1408 * After generating some load on the machine.
1409 */
1410 if (verbose > 1) {
1411 static u64 n;
1412 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1413 id, perf_evsel__name(evsel), ++n);
1414 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001415 return NULL;
1416 }
1417
1418 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1419 trace__read_syscall_info(trace, id))
1420 goto out_cant_read;
1421
1422 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1423 goto out_cant_read;
1424
1425 return &trace->syscalls.table[id];
1426
1427out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001428 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001429 fprintf(trace->output, "Problems reading syscall %d", id);
1430 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1431 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1432 fputs(" information\n", trace->output);
1433 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001434 return NULL;
1435}
1436
David Ahernbf2575c2013-10-08 21:26:53 -06001437static void thread__update_stats(struct thread_trace *ttrace,
1438 int id, struct perf_sample *sample)
1439{
1440 struct int_node *inode;
1441 struct stats *stats;
1442 u64 duration = 0;
1443
1444 inode = intlist__findnew(ttrace->syscall_stats, id);
1445 if (inode == NULL)
1446 return;
1447
1448 stats = inode->priv;
1449 if (stats == NULL) {
1450 stats = malloc(sizeof(struct stats));
1451 if (stats == NULL)
1452 return;
1453 init_stats(stats);
1454 inode->priv = stats;
1455 }
1456
1457 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1458 duration = sample->time - ttrace->entry_time;
1459
1460 update_stats(stats, duration);
1461}
1462
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001463static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1464{
1465 struct thread_trace *ttrace;
1466 u64 duration;
1467 size_t printed;
1468
1469 if (trace->current == NULL)
1470 return 0;
1471
1472 ttrace = thread__priv(trace->current);
1473
1474 if (!ttrace->entry_pending)
1475 return 0;
1476
1477 duration = sample->time - ttrace->entry_time;
1478
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001479 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001480 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1481 ttrace->entry_pending = false;
1482
1483 return printed;
1484}
1485
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001486static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001487 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001488 struct perf_sample *sample)
1489{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001490 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001491 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001492 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001493 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001494 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001495 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001496 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001497
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001498 if (sc == NULL)
1499 return -1;
1500
David Ahern8fb598e2013-09-28 13:13:00 -06001501 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001502 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001503 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001504 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001505
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001506 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001507
1508 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001509 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001510 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001511 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001512 }
1513
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001514 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001515 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001516
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001517 ttrace->entry_time = sample->time;
1518 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001519 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001521 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001522 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001523
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001524 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001525 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001526 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001527 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001528 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001529 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001530 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001531 /* See trace__vfs_getname & trace__sys_exit */
1532 ttrace->filename.pending_open = false;
1533 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001534
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001535 if (trace->current != thread) {
1536 thread__put(trace->current);
1537 trace->current = thread__get(thread);
1538 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001539 err = 0;
1540out_put:
1541 thread__put(thread);
1542 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001543}
1544
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001545static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1546 struct perf_sample *sample,
1547 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001548{
1549 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001550
1551 if (machine__resolve(trace->host, &al, sample) < 0 ||
1552 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1553 return -1;
1554
1555 return 0;
1556}
1557
1558static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1559{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001560 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001561 const unsigned int print_opts = EVSEL__PRINT_SYM |
1562 EVSEL__PRINT_DSO |
1563 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001564
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001565 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001566}
1567
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001568static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001569 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001570 struct perf_sample *sample)
1571{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001572 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001573 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001574 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001575 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001576 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001577 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001578 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001579
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001580 if (sc == NULL)
1581 return -1;
1582
David Ahern8fb598e2013-09-28 13:13:00 -06001583 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001584 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001585 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001586 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001587
David Ahernbf2575c2013-10-08 21:26:53 -06001588 if (trace->summary)
1589 thread__update_stats(ttrace, id, sample);
1590
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001591 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001592
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001593 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001594 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1595 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001596 ++trace->stats.vfs_getname;
1597 }
1598
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001599 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001600 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001601 if (trace__filter_duration(trace, duration))
1602 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001603 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001604 } else if (trace->duration_filter)
1605 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001606
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001607 if (sample->callchain) {
1608 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1609 if (callchain_ret == 0) {
1610 if (callchain_cursor.nr < trace->min_stack)
1611 goto out;
1612 callchain_ret = 1;
1613 }
1614 }
1615
David Ahernfd2eaba2013-11-12 09:31:15 -07001616 if (trace->summary_only)
1617 goto out;
1618
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001619 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001620
1621 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001622 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001623 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001624 fprintf(trace->output, " ... [");
1625 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1626 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001627 }
1628
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001629 if (sc->fmt == NULL) {
1630signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001631 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001632 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001633 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001634 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001635 *e = audit_errno_to_name(-ret);
1636
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001637 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001638 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001639 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001640 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001641 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001642 else if (sc->fmt->errpid) {
1643 struct thread *child = machine__find_thread(trace->host, ret, ret);
1644
1645 if (child != NULL) {
1646 fprintf(trace->output, ") = %ld", ret);
1647 if (child->comm_set)
1648 fprintf(trace->output, " (%s)", thread__comm_str(child));
1649 thread__put(child);
1650 }
1651 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001652 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001653
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001654 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001655
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001656 if (callchain_ret > 0)
1657 trace__fprintf_callchain(trace, sample);
1658 else if (callchain_ret < 0)
1659 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001660out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001661 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001662 err = 0;
1663out_put:
1664 thread__put(thread);
1665 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001666}
1667
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001668static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001669 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001670 struct perf_sample *sample)
1671{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001672 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1673 struct thread_trace *ttrace;
1674 size_t filename_len, entry_str_len, to_move;
1675 ssize_t remaining_space;
1676 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001677 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001678
1679 if (!thread)
1680 goto out;
1681
1682 ttrace = thread__priv(thread);
1683 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001684 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001685
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001686 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001687 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001688 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001689
1690 if (ttrace->filename.namelen < filename_len) {
1691 char *f = realloc(ttrace->filename.name, filename_len + 1);
1692
1693 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001694 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001695
1696 ttrace->filename.namelen = filename_len;
1697 ttrace->filename.name = f;
1698 }
1699
1700 strcpy(ttrace->filename.name, filename);
1701 ttrace->filename.pending_open = true;
1702
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001703 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001704 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001705
1706 entry_str_len = strlen(ttrace->entry_str);
1707 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1708 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001709 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001710
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001711 if (filename_len > (size_t)remaining_space) {
1712 filename += filename_len - remaining_space;
1713 filename_len = remaining_space;
1714 }
1715
1716 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1717 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1718 memmove(pos + filename_len, pos, to_move);
1719 memcpy(pos, filename, filename_len);
1720
1721 ttrace->filename.ptr = 0;
1722 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001723out_put:
1724 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001725out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001726 return 0;
1727}
1728
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001729static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001730 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001731 struct perf_sample *sample)
1732{
1733 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1734 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001735 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001736 sample->pid,
1737 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001738 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001739
1740 if (ttrace == NULL)
1741 goto out_dump;
1742
1743 ttrace->runtime_ms += runtime_ms;
1744 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001745out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001746 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001747 return 0;
1748
1749out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001750 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001751 evsel->name,
1752 perf_evsel__strval(evsel, sample, "comm"),
1753 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1754 runtime,
1755 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001756 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001757}
1758
Wang Nan1d6c9402016-02-26 09:31:55 +00001759static void bpf_output__printer(enum binary_printer_ops op,
1760 unsigned int val, void *extra)
1761{
1762 FILE *output = extra;
1763 unsigned char ch = (unsigned char)val;
1764
1765 switch (op) {
1766 case BINARY_PRINT_CHAR_DATA:
1767 fprintf(output, "%c", isprint(ch) ? ch : '.');
1768 break;
1769 case BINARY_PRINT_DATA_BEGIN:
1770 case BINARY_PRINT_LINE_BEGIN:
1771 case BINARY_PRINT_ADDR:
1772 case BINARY_PRINT_NUM_DATA:
1773 case BINARY_PRINT_NUM_PAD:
1774 case BINARY_PRINT_SEP:
1775 case BINARY_PRINT_CHAR_PAD:
1776 case BINARY_PRINT_LINE_END:
1777 case BINARY_PRINT_DATA_END:
1778 default:
1779 break;
1780 }
1781}
1782
1783static void bpf_output__fprintf(struct trace *trace,
1784 struct perf_sample *sample)
1785{
1786 print_binary(sample->raw_data, sample->raw_size, 8,
1787 bpf_output__printer, trace->output);
1788}
1789
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001790static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1791 union perf_event *event __maybe_unused,
1792 struct perf_sample *sample)
1793{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001794 int callchain_ret = 0;
1795
1796 if (sample->callchain) {
1797 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1798 if (callchain_ret == 0) {
1799 if (callchain_cursor.nr < trace->min_stack)
1800 goto out;
1801 callchain_ret = 1;
1802 }
1803 }
1804
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001805 trace__printf_interrupted_entry(trace, sample);
1806 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001807
1808 if (trace->trace_syscalls)
1809 fprintf(trace->output, "( ): ");
1810
1811 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001812
Wang Nan1d6c9402016-02-26 09:31:55 +00001813 if (perf_evsel__is_bpf_output(evsel)) {
1814 bpf_output__fprintf(trace, sample);
1815 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001816 event_format__fprintf(evsel->tp_format, sample->cpu,
1817 sample->raw_data, sample->raw_size,
1818 trace->output);
1819 }
1820
1821 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001822
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001823 if (callchain_ret > 0)
1824 trace__fprintf_callchain(trace, sample);
1825 else if (callchain_ret < 0)
1826 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1827out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001828 return 0;
1829}
1830
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001831static void print_location(FILE *f, struct perf_sample *sample,
1832 struct addr_location *al,
1833 bool print_dso, bool print_sym)
1834{
1835
Namhyung Kimbb963e12017-02-17 17:17:38 +09001836 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001837 fprintf(f, "%s@", al->map->dso->long_name);
1838
Namhyung Kimbb963e12017-02-17 17:17:38 +09001839 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001840 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001841 al->addr - al->sym->start);
1842 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001843 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001844 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001845 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001846}
1847
1848static int trace__pgfault(struct trace *trace,
1849 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001850 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001851 struct perf_sample *sample)
1852{
1853 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001854 struct addr_location al;
1855 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001856 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001857 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001858 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001859
1860 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001861
1862 if (sample->callchain) {
1863 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1864 if (callchain_ret == 0) {
1865 if (callchain_cursor.nr < trace->min_stack)
1866 goto out_put;
1867 callchain_ret = 1;
1868 }
1869 }
1870
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001871 ttrace = thread__trace(thread, trace->output);
1872 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001873 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001874
1875 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1876 ttrace->pfmaj++;
1877 else
1878 ttrace->pfmin++;
1879
1880 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001881 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001882
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001883 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001884 sample->ip, &al);
1885
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001886 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001887
1888 fprintf(trace->output, "%sfault [",
1889 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1890 "maj" : "min");
1891
1892 print_location(trace->output, sample, &al, false, true);
1893
1894 fprintf(trace->output, "] => ");
1895
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001896 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001897 sample->addr, &al);
1898
1899 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001900 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001901 MAP__FUNCTION, sample->addr, &al);
1902
1903 if (al.map)
1904 map_type = 'x';
1905 else
1906 map_type = '?';
1907 }
1908
1909 print_location(trace->output, sample, &al, true, false);
1910
1911 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001912
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001913 if (callchain_ret > 0)
1914 trace__fprintf_callchain(trace, sample);
1915 else if (callchain_ret < 0)
1916 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001917out:
1918 err = 0;
1919out_put:
1920 thread__put(thread);
1921 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001922}
1923
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001924static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001925 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001926 struct perf_sample *sample)
1927{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001928 /*
1929 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1930 * and don't use sample->time unconditionally, we may end up having
1931 * some other event in the future without PERF_SAMPLE_TIME for good
1932 * reason, i.e. we may not be interested in its timestamps, just in
1933 * it taking place, picking some piece of information when it
1934 * appears in our event stream (vfs_getname comes to mind).
1935 */
1936 if (trace->base_time == 0 && !trace->full_time &&
1937 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001938 trace->base_time = sample->time;
1939}
1940
David Ahern6810fc92013-08-28 22:29:52 -06001941static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001942 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001943 struct perf_sample *sample,
1944 struct perf_evsel *evsel,
1945 struct machine *machine __maybe_unused)
1946{
1947 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001948 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001949 int err = 0;
1950
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001951 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001952
David Ahernaa07df62016-11-25 09:29:52 -07001953 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1954 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001955 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06001956
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001957 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001958
David Ahern31605652013-12-04 19:41:41 -07001959 if (handler) {
1960 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001961 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001962 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001963out:
1964 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06001965 return err;
1966}
1967
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001968static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001969{
1970 unsigned int rec_argc, i, j;
1971 const char **rec_argv;
1972 const char * const record_args[] = {
1973 "record",
1974 "-R",
1975 "-m", "1024",
1976 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001977 };
1978
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001979 const char * const sc_args[] = { "-e", };
1980 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1981 const char * const majpf_args[] = { "-e", "major-faults" };
1982 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1983 const char * const minpf_args[] = { "-e", "minor-faults" };
1984 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1985
David Ahern9aca7f12013-12-04 19:41:39 -07001986 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001987 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1988 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001989 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1990
1991 if (rec_argv == NULL)
1992 return -ENOMEM;
1993
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001994 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001995 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001996 rec_argv[j++] = record_args[i];
1997
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001998 if (trace->trace_syscalls) {
1999 for (i = 0; i < sc_args_nr; i++)
2000 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002001
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002002 /* event string may be different for older kernels - e.g., RHEL6 */
2003 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2004 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2005 else if (is_valid_tracepoint("syscalls:sys_enter"))
2006 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2007 else {
2008 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2009 return -1;
2010 }
David Ahern9aca7f12013-12-04 19:41:39 -07002011 }
David Ahern9aca7f12013-12-04 19:41:39 -07002012
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002013 if (trace->trace_pgfaults & TRACE_PFMAJ)
2014 for (i = 0; i < majpf_args_nr; i++)
2015 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002016
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002017 if (trace->trace_pgfaults & TRACE_PFMIN)
2018 for (i = 0; i < minpf_args_nr; i++)
2019 rec_argv[j++] = minpf_args[i];
2020
2021 for (i = 0; i < (unsigned int)argc; i++)
2022 rec_argv[j++] = argv[i];
2023
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002024 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002025}
2026
David Ahernbf2575c2013-10-08 21:26:53 -06002027static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2028
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002029static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002030{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002031 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002032
2033 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002034 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002035
2036 if (perf_evsel__field(evsel, "pathname") == NULL) {
2037 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002038 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002039 }
2040
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002041 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002042 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002043 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002044}
2045
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002046static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002047{
2048 struct perf_evsel *evsel;
2049 struct perf_event_attr attr = {
2050 .type = PERF_TYPE_SOFTWARE,
2051 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002052 };
2053
2054 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002055 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002056
2057 event_attr_init(&attr);
2058
2059 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002060 if (evsel)
2061 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002062
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002063 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002064}
2065
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002066static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2067{
2068 const u32 type = event->header.type;
2069 struct perf_evsel *evsel;
2070
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002071 if (type != PERF_RECORD_SAMPLE) {
2072 trace__process_event(trace, trace->host, event, sample);
2073 return;
2074 }
2075
2076 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2077 if (evsel == NULL) {
2078 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2079 return;
2080 }
2081
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002082 trace__set_base_time(trace, evsel, sample);
2083
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002084 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2085 sample->raw_data == NULL) {
2086 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2087 perf_evsel__name(evsel), sample->tid,
2088 sample->cpu, sample->raw_size);
2089 } else {
2090 tracepoint_handler handler = evsel->handler;
2091 handler(trace, evsel, event, sample);
2092 }
2093}
2094
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002095static int trace__add_syscall_newtp(struct trace *trace)
2096{
2097 int ret = -1;
2098 struct perf_evlist *evlist = trace->evlist;
2099 struct perf_evsel *sys_enter, *sys_exit;
2100
2101 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2102 if (sys_enter == NULL)
2103 goto out;
2104
2105 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2106 goto out_delete_sys_enter;
2107
2108 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2109 if (sys_exit == NULL)
2110 goto out_delete_sys_enter;
2111
2112 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2113 goto out_delete_sys_exit;
2114
2115 perf_evlist__add(evlist, sys_enter);
2116 perf_evlist__add(evlist, sys_exit);
2117
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002118 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002119 /*
2120 * We're interested only in the user space callchain
2121 * leading to the syscall, allow overriding that for
2122 * debugging reasons using --kernel_syscall_callchains
2123 */
2124 sys_exit->attr.exclude_callchain_kernel = 1;
2125 }
2126
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002127 trace->syscalls.events.sys_enter = sys_enter;
2128 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002129
2130 ret = 0;
2131out:
2132 return ret;
2133
2134out_delete_sys_exit:
2135 perf_evsel__delete_priv(sys_exit);
2136out_delete_sys_enter:
2137 perf_evsel__delete_priv(sys_enter);
2138 goto out;
2139}
2140
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002141static int trace__set_ev_qualifier_filter(struct trace *trace)
2142{
2143 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002144 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002145 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2146 trace->ev_qualifier_ids.nr,
2147 trace->ev_qualifier_ids.entries);
2148
2149 if (filter == NULL)
2150 goto out_enomem;
2151
Mathieu Poirier3541c032016-09-16 08:44:04 -06002152 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2153 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002154 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002155 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002156 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002157
2158 free(filter);
2159out:
2160 return err;
2161out_enomem:
2162 errno = ENOMEM;
2163 goto out;
2164}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002165
Namhyung Kimf15eb532012-10-05 14:02:16 +09002166static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002167{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002168 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002169 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002170 int err = -1, i;
2171 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002172 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002173 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002174
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002175 trace->live = true;
2176
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002177 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002178 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002179
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002180 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002181 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002182
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002183 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2184 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2185 if (pgfault_maj == NULL)
2186 goto out_error_mem;
2187 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002188 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002189
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002190 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2191 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2192 if (pgfault_min == NULL)
2193 goto out_error_mem;
2194 perf_evlist__add(evlist, pgfault_min);
2195 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002196
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002197 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002198 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2199 trace__sched_stat_runtime))
2200 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002201
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002202 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2203 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002204 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002205 goto out_delete_evlist;
2206 }
2207
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002208 err = trace__symbols_init(trace, evlist);
2209 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002210 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002211 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002212 }
2213
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002214 perf_evlist__config(evlist, &trace->opts, NULL);
2215
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002216 if (callchain_param.enabled) {
2217 bool use_identifier = false;
2218
2219 if (trace->syscalls.events.sys_exit) {
2220 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2221 &trace->opts, &callchain_param);
2222 use_identifier = true;
2223 }
2224
2225 if (pgfault_maj) {
2226 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2227 use_identifier = true;
2228 }
2229
2230 if (pgfault_min) {
2231 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2232 use_identifier = true;
2233 }
2234
2235 if (use_identifier) {
2236 /*
2237 * Now we have evsels with different sample_ids, use
2238 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2239 * from a fixed position in each ring buffer record.
2240 *
2241 * As of this the changeset introducing this comment, this
2242 * isn't strictly needed, as the fields that can come before
2243 * PERF_SAMPLE_ID are all used, but we'll probably disable
2244 * some of those for things like copying the payload of
2245 * pointer syscall arguments, and for vfs_getname we don't
2246 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2247 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2248 */
2249 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2250 perf_evlist__reset_sample_bit(evlist, ID);
2251 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002252 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002253
Namhyung Kimf15eb532012-10-05 14:02:16 +09002254 signal(SIGCHLD, sig_handler);
2255 signal(SIGINT, sig_handler);
2256
2257 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002258 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002259 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002260 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002261 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002262 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002263 }
2264 }
2265
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002266 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002267 if (err < 0)
2268 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002269
Wang Nanba504232016-02-26 09:31:54 +00002270 err = bpf__apply_obj_config();
2271 if (err) {
2272 char errbuf[BUFSIZ];
2273
2274 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2275 pr_err("ERROR: Apply config to BPF failed: %s\n",
2276 errbuf);
2277 goto out_error_open;
2278 }
2279
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002280 /*
2281 * Better not use !target__has_task() here because we need to cover the
2282 * case where no threads were specified in the command line, but a
2283 * workload was, and in that case we will fill in the thread_map when
2284 * we fork the workload in perf_evlist__prepare_workload.
2285 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002286 if (trace->filter_pids.nr > 0)
2287 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002288 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002289 err = perf_evlist__set_filter_pid(evlist, getpid());
2290
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002291 if (err < 0)
2292 goto out_error_mem;
2293
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002294 if (trace->ev_qualifier_ids.nr > 0) {
2295 err = trace__set_ev_qualifier_filter(trace);
2296 if (err < 0)
2297 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002298
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002299 pr_debug("event qualifier tracepoint filter: %s\n",
2300 trace->syscalls.events.sys_exit->filter);
2301 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002302
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002303 err = perf_evlist__apply_filters(evlist, &evsel);
2304 if (err < 0)
2305 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002306
Jiri Olsaf8850372013-11-28 17:57:22 +01002307 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002308 if (err < 0)
2309 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002310
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002311 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002312 perf_evlist__enable(evlist);
2313
Namhyung Kimf15eb532012-10-05 14:02:16 +09002314 if (forks)
2315 perf_evlist__start_workload(evlist);
2316
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002317 if (trace->opts.initial_delay) {
2318 usleep(trace->opts.initial_delay * 1000);
2319 perf_evlist__enable(evlist);
2320 }
2321
Jiri Olsae13798c2015-06-23 00:36:02 +02002322 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002323 evlist->threads->nr > 1 ||
2324 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002325again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002326 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002327
2328 for (i = 0; i < evlist->nr_mmaps; i++) {
2329 union perf_event *event;
2330
2331 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002332 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002334 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002335
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002336 err = perf_evlist__parse_sample(evlist, event, &sample);
2337 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002338 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002339 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002340 }
2341
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002342 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002343next_event:
2344 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002345
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002346 if (interrupted)
2347 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002348
2349 if (done && !draining) {
2350 perf_evlist__disable(evlist);
2351 draining = true;
2352 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002353 }
2354 }
2355
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002356 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002357 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002358
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002359 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2360 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2361 draining = true;
2362
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002363 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002364 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002365 } else {
2366 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002367 }
2368
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002369out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002370 thread__zput(trace->current);
2371
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002372 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002373
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002374 if (!err) {
2375 if (trace->summary)
2376 trace__fprintf_thread_summary(trace, trace->output);
2377
2378 if (trace->show_tool_stats) {
2379 fprintf(trace->output, "Stats:\n "
2380 " vfs_getname : %" PRIu64 "\n"
2381 " proc_getname: %" PRIu64 "\n",
2382 trace->stats.vfs_getname,
2383 trace->stats.proc_getname);
2384 }
2385 }
David Ahernbf2575c2013-10-08 21:26:53 -06002386
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002387out_delete_evlist:
2388 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002389 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002390 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002391 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002392{
2393 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002394
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002395out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002396 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002397 goto out_error;
2398
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002399out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002400 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002401 goto out_error;
2402
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002403out_error_mmap:
2404 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2405 goto out_error;
2406
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002407out_error_open:
2408 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2409
2410out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002411 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302412 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002413
2414out_error_apply_filters:
2415 fprintf(trace->output,
2416 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2417 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002418 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002419 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002420}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002421out_error_mem:
2422 fprintf(trace->output, "Not enough memory to run!\n");
2423 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002424
2425out_errno:
2426 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2427 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002428}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429
David Ahern6810fc92013-08-28 22:29:52 -06002430static int trace__replay(struct trace *trace)
2431{
2432 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002433 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002434 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002435 struct perf_data_file file = {
2436 .path = input_name,
2437 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002438 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002439 };
David Ahern6810fc92013-08-28 22:29:52 -06002440 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002441 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002442 int err = -1;
2443
2444 trace->tool.sample = trace__process_sample;
2445 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002446 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002447 trace->tool.comm = perf_event__process_comm;
2448 trace->tool.exit = perf_event__process_exit;
2449 trace->tool.fork = perf_event__process_fork;
2450 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302451 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002452 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302453 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002454
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002455 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002456 trace->tool.ordering_requires_timestamps = true;
2457
2458 /* add tid to output */
2459 trace->multiple_threads = true;
2460
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002461 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002462 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002463 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002464
David Ahernaa07df62016-11-25 09:29:52 -07002465 if (trace->opts.target.pid)
2466 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2467
2468 if (trace->opts.target.tid)
2469 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2470
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002471 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002472 goto out;
2473
David Ahern8fb598e2013-09-28 13:13:00 -06002474 trace->host = &session->machines.host;
2475
David Ahern6810fc92013-08-28 22:29:52 -06002476 err = perf_session__set_tracepoints_handlers(session, handlers);
2477 if (err)
2478 goto out;
2479
Namhyung Kim003824e2013-11-12 15:25:00 +09002480 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2481 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002482 /* older kernels have syscalls tp versus raw_syscalls */
2483 if (evsel == NULL)
2484 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2485 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002486
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002487 if (evsel &&
2488 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2489 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002490 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2491 goto out;
2492 }
2493
2494 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2495 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002496 if (evsel == NULL)
2497 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2498 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002499 if (evsel &&
2500 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2501 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002502 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002503 goto out;
2504 }
2505
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002506 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002507 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2508 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2509 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2510 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2511 evsel->handler = trace__pgfault;
2512 }
2513
David Ahern6810fc92013-08-28 22:29:52 -06002514 setup_pager();
2515
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002516 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002517 if (err)
2518 pr_err("Failed to process events, error %d", err);
2519
David Ahernbf2575c2013-10-08 21:26:53 -06002520 else if (trace->summary)
2521 trace__fprintf_thread_summary(trace, trace->output);
2522
David Ahern6810fc92013-08-28 22:29:52 -06002523out:
2524 perf_session__delete(session);
2525
2526 return err;
2527}
2528
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002529static size_t trace__fprintf_threads_header(FILE *fp)
2530{
2531 size_t printed;
2532
Pekka Enberg99ff7152013-11-12 16:42:14 +02002533 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002534
2535 return printed;
2536}
2537
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002538DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2539 struct stats *stats;
2540 double msecs;
2541 int syscall;
2542)
2543{
2544 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2545 struct stats *stats = source->priv;
2546
2547 entry->syscall = source->i;
2548 entry->stats = stats;
2549 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2550}
2551
David Ahernbf2575c2013-10-08 21:26:53 -06002552static size_t thread__dump_stats(struct thread_trace *ttrace,
2553 struct trace *trace, FILE *fp)
2554{
David Ahernbf2575c2013-10-08 21:26:53 -06002555 size_t printed = 0;
2556 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002557 struct rb_node *nd;
2558 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002559
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002560 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002561 return 0;
2562
2563 printed += fprintf(fp, "\n");
2564
Milian Wolff834fd462015-08-06 11:24:29 +02002565 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2566 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2567 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002568
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002569 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002570 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002571 if (stats) {
2572 double min = (double)(stats->min) / NSEC_PER_MSEC;
2573 double max = (double)(stats->max) / NSEC_PER_MSEC;
2574 double avg = avg_stats(stats);
2575 double pct;
2576 u64 n = (u64) stats->n;
2577
2578 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2579 avg /= NSEC_PER_MSEC;
2580
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002581 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002582 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002583 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002584 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002585 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002586 }
David Ahernbf2575c2013-10-08 21:26:53 -06002587 }
2588
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002589 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002590 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002591
2592 return printed;
2593}
2594
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002595static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002596{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002597 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002598 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002599 double ratio;
2600
2601 if (ttrace == NULL)
2602 return 0;
2603
2604 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2605
Pekka Enberg15e65c62013-11-14 18:43:30 +02002606 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002607 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002608 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002609 if (ttrace->pfmaj)
2610 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2611 if (ttrace->pfmin)
2612 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002613 if (trace->sched)
2614 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2615 else if (fputc('\n', fp) != EOF)
2616 ++printed;
2617
David Ahernbf2575c2013-10-08 21:26:53 -06002618 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002619
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002620 return printed;
2621}
David Ahern896cbb52013-09-28 13:12:59 -06002622
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002623static unsigned long thread__nr_events(struct thread_trace *ttrace)
2624{
2625 return ttrace ? ttrace->nr_events : 0;
2626}
2627
2628DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2629 struct thread *thread;
2630)
2631{
2632 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002633}
2634
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002635static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2636{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002637 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2638 size_t printed = trace__fprintf_threads_header(fp);
2639 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002640
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002641 if (threads == NULL) {
2642 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2643 return 0;
2644 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002645
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002646 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002647 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2648
2649 resort_rb__delete(threads);
2650
2651 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002652}
2653
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002654static int trace__set_duration(const struct option *opt, const char *str,
2655 int unset __maybe_unused)
2656{
2657 struct trace *trace = opt->value;
2658
2659 trace->duration_filter = atof(str);
2660 return 0;
2661}
2662
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002663static int trace__set_filter_pids(const struct option *opt, const char *str,
2664 int unset __maybe_unused)
2665{
2666 int ret = -1;
2667 size_t i;
2668 struct trace *trace = opt->value;
2669 /*
2670 * FIXME: introduce a intarray class, plain parse csv and create a
2671 * { int nr, int entries[] } struct...
2672 */
2673 struct intlist *list = intlist__new(str);
2674
2675 if (list == NULL)
2676 return -1;
2677
2678 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2679 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2680
2681 if (trace->filter_pids.entries == NULL)
2682 goto out;
2683
2684 trace->filter_pids.entries[0] = getpid();
2685
2686 for (i = 1; i < trace->filter_pids.nr; ++i)
2687 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2688
2689 intlist__delete(list);
2690 ret = 0;
2691out:
2692 return ret;
2693}
2694
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002695static int trace__open_output(struct trace *trace, const char *filename)
2696{
2697 struct stat st;
2698
2699 if (!stat(filename, &st) && st.st_size) {
2700 char oldname[PATH_MAX];
2701
2702 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2703 unlink(oldname);
2704 rename(filename, oldname);
2705 }
2706
2707 trace->output = fopen(filename, "w");
2708
2709 return trace->output == NULL ? -errno : 0;
2710}
2711
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002712static int parse_pagefaults(const struct option *opt, const char *str,
2713 int unset __maybe_unused)
2714{
2715 int *trace_pgfaults = opt->value;
2716
2717 if (strcmp(str, "all") == 0)
2718 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2719 else if (strcmp(str, "maj") == 0)
2720 *trace_pgfaults |= TRACE_PFMAJ;
2721 else if (strcmp(str, "min") == 0)
2722 *trace_pgfaults |= TRACE_PFMIN;
2723 else
2724 return -1;
2725
2726 return 0;
2727}
2728
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002729static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2730{
2731 struct perf_evsel *evsel;
2732
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002733 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002734 evsel->handler = handler;
2735}
2736
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002737/*
2738 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2739 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2740 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2741 *
2742 * It'd be better to introduce a parse_options() variant that would return a
2743 * list with the terms it didn't match to an event...
2744 */
2745static int trace__parse_events_option(const struct option *opt, const char *str,
2746 int unset __maybe_unused)
2747{
2748 struct trace *trace = (struct trace *)opt->value;
2749 const char *s = str;
2750 char *sep = NULL, *lists[2] = { NULL, NULL, };
2751 int len = strlen(str), err = -1, list;
2752 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2753 char group_name[PATH_MAX];
2754
2755 if (strace_groups_dir == NULL)
2756 return -1;
2757
2758 if (*s == '!') {
2759 ++s;
2760 trace->not_ev_qualifier = true;
2761 }
2762
2763 while (1) {
2764 if ((sep = strchr(s, ',')) != NULL)
2765 *sep = '\0';
2766
2767 list = 0;
2768 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2769 list = 1;
2770 } else {
2771 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2772 if (access(group_name, R_OK) == 0)
2773 list = 1;
2774 }
2775
2776 if (lists[list]) {
2777 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2778 } else {
2779 lists[list] = malloc(len);
2780 if (lists[list] == NULL)
2781 goto out;
2782 strcpy(lists[list], s);
2783 }
2784
2785 if (!sep)
2786 break;
2787
2788 *sep = ',';
2789 s = sep + 1;
2790 }
2791
2792 if (lists[1] != NULL) {
2793 struct strlist_config slist_config = {
2794 .dirname = strace_groups_dir,
2795 };
2796
2797 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2798 if (trace->ev_qualifier == NULL) {
2799 fputs("Not enough memory to parse event qualifier", trace->output);
2800 goto out;
2801 }
2802
2803 if (trace__validate_ev_qualifier(trace))
2804 goto out;
2805 }
2806
2807 err = 0;
2808
2809 if (lists[0]) {
2810 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2811 "event selector. use 'perf list' to list available events",
2812 parse_events_option);
2813 err = parse_events_option(&o, lists[0], 0);
2814 }
2815out:
2816 if (sep)
2817 *sep = ',';
2818
2819 return err;
2820}
2821
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002822int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002823{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002824 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002825 "perf trace [<options>] [<command>]",
2826 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002827 "perf trace record [<options>] [<command>]",
2828 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002829 NULL
2830 };
2831 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002832 .syscalls = {
2833 . max = -1,
2834 },
2835 .opts = {
2836 .target = {
2837 .uid = UINT_MAX,
2838 .uses_mmap = true,
2839 },
2840 .user_freq = UINT_MAX,
2841 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002842 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002843 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002844 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002845 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002846 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002847 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002848 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002849 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002850 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002851 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002852 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002853 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002854 OPT_CALLBACK('e', "event", &trace, "event",
2855 "event/syscall selector. use 'perf list' to list available events",
2856 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002857 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2858 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002859 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002860 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2861 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002862 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002863 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002864 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2865 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002866 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002867 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002868 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2869 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002870 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002871 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002872 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002873 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002874 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002875 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002876 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2877 "number of mmap data pages",
2878 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002879 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002880 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002881 OPT_CALLBACK(0, "duration", &trace, "float",
2882 "show only events with duration > N.M ms",
2883 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002884 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002885 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002886 OPT_BOOLEAN('T', "time", &trace.full_time,
2887 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002888 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2889 "Show only syscall summary with statistics"),
2890 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2891 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002892 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2893 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002894 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002895 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002896 OPT_CALLBACK(0, "call-graph", &trace.opts,
2897 "record_mode[,record_size]", record_callchain_help,
2898 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002899 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2900 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002901 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2902 "Set the minimum stack depth when parsing the callchain, "
2903 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002904 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2905 "Set the maximum stack depth when parsing the callchain, "
2906 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002907 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002908 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2909 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002910 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2911 "ms to wait before starting measurement after program "
2912 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002913 OPT_END()
2914 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002915 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002916 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002917 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002918 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002919 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002920
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002921 signal(SIGSEGV, sighandler_dump_stack);
2922 signal(SIGFPE, sighandler_dump_stack);
2923
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002924 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002925 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002926
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002927 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002928 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002929 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002930 goto out;
2931 }
2932
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002933 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2934 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002935
Wang Nand7888572016-04-08 15:07:24 +00002936 err = bpf__setup_stdout(trace.evlist);
2937 if (err) {
2938 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2939 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2940 goto out;
2941 }
2942
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002943 err = -1;
2944
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002945 if (trace.trace_pgfaults) {
2946 trace.opts.sample_address = true;
2947 trace.opts.sample_time = true;
2948 }
2949
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002950 if (trace.opts.mmap_pages == UINT_MAX)
2951 mmap_pages_user_set = false;
2952
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002953 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002954 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002955 max_stack_user_set = false;
2956 }
2957
2958#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002959 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002960 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2961#endif
2962
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002963 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002964 if (!mmap_pages_user_set && geteuid() == 0)
2965 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2966
Milian Wolff566a0882016-04-08 13:34:15 +02002967 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002968 }
Milian Wolff566a0882016-04-08 13:34:15 +02002969
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002970 if (trace.evlist->nr_entries > 0)
2971 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2972
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002973 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2974 return trace__record(&trace, argc-1, &argv[1]);
2975
2976 /* summary_only implies summary option, but don't overwrite summary if set */
2977 if (trace.summary_only)
2978 trace.summary = trace.summary_only;
2979
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002980 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2981 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002982 pr_err("Please specify something to trace.\n");
2983 return -1;
2984 }
2985
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002986 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002987 pr_err("The -e option can't be used with --no-syscalls.\n");
2988 goto out;
2989 }
2990
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002991 if (output_name != NULL) {
2992 err = trace__open_output(&trace, output_name);
2993 if (err < 0) {
2994 perror("failed to create output file");
2995 goto out;
2996 }
2997 }
2998
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002999 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3000
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003001 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003002 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003003 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003004 fprintf(trace.output, "%s", bf);
3005 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003006 }
3007
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003008 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003009 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003010 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003011 fprintf(trace.output, "%s", bf);
3012 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003013 }
3014
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003015 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003016 trace.opts.target.system_wide = true;
3017
David Ahern6810fc92013-08-28 22:29:52 -06003018 if (input_name)
3019 err = trace__replay(&trace);
3020 else
3021 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003022
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003023out_close:
3024 if (output_name != NULL)
3025 fclose(trace.output);
3026out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003027 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003028}