blob: 5c50fe70d6b37379bd8b89b05d9df7899b9fc27d [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/filter.h>
45#include <linux/audit.h>
46#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030047#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030048#include <linux/stringify.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030049
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030050#ifndef O_CLOEXEC
51# define O_CLOEXEC 02000000
52#endif
53
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030054struct trace {
55 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030056 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030057 struct {
58 int max;
59 struct syscall *table;
60 struct {
61 struct perf_evsel *sys_enter,
62 *sys_exit;
63 } events;
64 } syscalls;
65 struct record_opts opts;
66 struct perf_evlist *evlist;
67 struct machine *host;
68 struct thread *current;
69 u64 base_time;
70 FILE *output;
71 unsigned long nr_events;
72 struct strlist *ev_qualifier;
73 struct {
74 size_t nr;
75 int *entries;
76 } ev_qualifier_ids;
77 struct intlist *tid_list;
78 struct intlist *pid_list;
79 struct {
80 size_t nr;
81 pid_t *entries;
82 } filter_pids;
83 double duration_filter;
84 double runtime_ms;
85 struct {
86 u64 vfs_getname,
87 proc_getname;
88 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030089 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030090 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030091 bool not_ev_qualifier;
92 bool live;
93 bool full_time;
94 bool sched;
95 bool multiple_threads;
96 bool summary;
97 bool summary_only;
98 bool show_comm;
99 bool show_tool_stats;
100 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300101 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300102 bool force;
103 bool vfs_getname;
104 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300105 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300107
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300108struct tp_field {
109 int offset;
110 union {
111 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
112 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
113 };
114};
115
116#define TP_UINT_FIELD(bits) \
117static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
118{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500119 u##bits value; \
120 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
121 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300122}
123
124TP_UINT_FIELD(8);
125TP_UINT_FIELD(16);
126TP_UINT_FIELD(32);
127TP_UINT_FIELD(64);
128
129#define TP_UINT_FIELD__SWAPPED(bits) \
130static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
131{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500132 u##bits value; \
133 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300134 return bswap_##bits(value);\
135}
136
137TP_UINT_FIELD__SWAPPED(16);
138TP_UINT_FIELD__SWAPPED(32);
139TP_UINT_FIELD__SWAPPED(64);
140
141static int tp_field__init_uint(struct tp_field *field,
142 struct format_field *format_field,
143 bool needs_swap)
144{
145 field->offset = format_field->offset;
146
147 switch (format_field->size) {
148 case 1:
149 field->integer = tp_field__u8;
150 break;
151 case 2:
152 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
153 break;
154 case 4:
155 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
156 break;
157 case 8:
158 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
159 break;
160 default:
161 return -1;
162 }
163
164 return 0;
165}
166
167static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
168{
169 return sample->raw_data + field->offset;
170}
171
172static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
173{
174 field->offset = format_field->offset;
175 field->pointer = tp_field__ptr;
176 return 0;
177}
178
179struct syscall_tp {
180 struct tp_field id;
181 union {
182 struct tp_field args, ret;
183 };
184};
185
186static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
187 struct tp_field *field,
188 const char *name)
189{
190 struct format_field *format_field = perf_evsel__field(evsel, name);
191
192 if (format_field == NULL)
193 return -1;
194
195 return tp_field__init_uint(field, format_field, evsel->needs_swap);
196}
197
198#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
199 ({ struct syscall_tp *sc = evsel->priv;\
200 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
201
202static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
203 struct tp_field *field,
204 const char *name)
205{
206 struct format_field *format_field = perf_evsel__field(evsel, name);
207
208 if (format_field == NULL)
209 return -1;
210
211 return tp_field__init_ptr(field, format_field);
212}
213
214#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
215 ({ struct syscall_tp *sc = evsel->priv;\
216 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
217
218static void perf_evsel__delete_priv(struct perf_evsel *evsel)
219{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300220 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300221 perf_evsel__delete(evsel);
222}
223
Namhyung Kim96695d42013-11-12 08:51:45 -0300224static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
225{
226 evsel->priv = malloc(sizeof(struct syscall_tp));
227 if (evsel->priv != NULL) {
228 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
229 goto out_delete;
230
231 evsel->handler = handler;
232 return 0;
233 }
234
235 return -ENOMEM;
236
237out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300238 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300239 return -ENOENT;
240}
241
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300242static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300243{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245
David Ahern9aca7f12013-12-04 19:41:39 -0700246 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200247 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700248 evsel = perf_evsel__newtp("syscalls", direction);
249
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200250 if (IS_ERR(evsel))
251 return NULL;
252
253 if (perf_evsel__init_syscall_tp(evsel, handler))
254 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300255
256 return evsel;
257
258out_delete:
259 perf_evsel__delete_priv(evsel);
260 return NULL;
261}
262
263#define perf_evsel__sc_tp_uint(evsel, name, sample) \
264 ({ struct syscall_tp *fields = evsel->priv; \
265 fields->name.integer(&fields->name, sample); })
266
267#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
268 ({ struct syscall_tp *fields = evsel->priv; \
269 fields->name.pointer(&fields->name, sample); })
270
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271struct syscall_arg {
272 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300273 struct thread *thread;
274 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300275 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300276 u8 idx;
277 u8 mask;
278};
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300281 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282 int nr_entries;
283 const char **entries;
284};
285
286#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
287 .nr_entries = ARRAY_SIZE(array), \
288 .entries = array, \
289}
290
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300291#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
292 .offset = off, \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300297static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
298 const char *intfmt,
299 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300302 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303
304 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300305 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306
307 return scnprintf(bf, size, "%s", sa->entries[idx]);
308}
309
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300310static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
311 struct syscall_arg *arg)
312{
313 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
314}
315
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316#define SCA_STRARRAY syscall_arg__scnprintf_strarray
317
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300318#if defined(__i386__) || defined(__x86_64__)
319/*
320 * FIXME: Make this available to all arches as soon as the ioctl beautifier
321 * gets rewritten to support all arches.
322 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300323static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
324 struct syscall_arg *arg)
325{
326 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
327}
328
329#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300330#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300331
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300332static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
333 struct syscall_arg *arg);
334
335#define SCA_FD syscall_arg__scnprintf_fd
336
337static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
338 struct syscall_arg *arg)
339{
340 int fd = arg->val;
341
342 if (fd == AT_FDCWD)
343 return scnprintf(bf, size, "CWD");
344
345 return syscall_arg__scnprintf_fd(bf, size, arg);
346}
347
348#define SCA_FDAT syscall_arg__scnprintf_fd_at
349
350static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
351 struct syscall_arg *arg);
352
353#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
354
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300355static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300356 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300357{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300358 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300359}
360
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300361#define SCA_HEX syscall_arg__scnprintf_hex
362
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300363static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
364 struct syscall_arg *arg)
365{
366 return scnprintf(bf, size, "%d", arg->val);
367}
368
369#define SCA_INT syscall_arg__scnprintf_int
370
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300371static const char *bpf_cmd[] = {
372 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
373 "MAP_GET_NEXT_KEY", "PROG_LOAD",
374};
375static DEFINE_STRARRAY(bpf_cmd);
376
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300377static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
378static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300379
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300380static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
381static DEFINE_STRARRAY(itimers);
382
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300383static const char *keyctl_options[] = {
384 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
385 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
386 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
387 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
388 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
389};
390static DEFINE_STRARRAY(keyctl_options);
391
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300392static const char *whences[] = { "SET", "CUR", "END",
393#ifdef SEEK_DATA
394"DATA",
395#endif
396#ifdef SEEK_HOLE
397"HOLE",
398#endif
399};
400static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300401
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300402static const char *fcntl_cmds[] = {
403 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
404 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
405 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
406 "F_GETOWNER_UIDS",
407};
408static DEFINE_STRARRAY(fcntl_cmds);
409
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300410static const char *rlimit_resources[] = {
411 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
412 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
413 "RTTIME",
414};
415static DEFINE_STRARRAY(rlimit_resources);
416
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300417static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
418static DEFINE_STRARRAY(sighow);
419
David Ahern4f8c1b72013-09-22 19:45:00 -0600420static const char *clockid[] = {
421 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300422 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
423 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600424};
425static DEFINE_STRARRAY(clockid);
426
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300427static const char *socket_families[] = {
428 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
429 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
430 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
431 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
432 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
433 "ALG", "NFC", "VSOCK",
434};
435static DEFINE_STRARRAY(socket_families);
436
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300437static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
438 struct syscall_arg *arg)
439{
440 size_t printed = 0;
441 int mode = arg->val;
442
443 if (mode == F_OK) /* 0 */
444 return scnprintf(bf, size, "F");
445#define P_MODE(n) \
446 if (mode & n##_OK) { \
447 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
448 mode &= ~n##_OK; \
449 }
450
451 P_MODE(R);
452 P_MODE(W);
453 P_MODE(X);
454#undef P_MODE
455
456 if (mode)
457 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
458
459 return printed;
460}
461
462#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
463
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300464static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
465 struct syscall_arg *arg);
466
467#define SCA_FILENAME syscall_arg__scnprintf_filename
468
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300469static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
470 struct syscall_arg *arg)
471{
472 int printed = 0, flags = arg->val;
473
474#define P_FLAG(n) \
475 if (flags & O_##n) { \
476 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
477 flags &= ~O_##n; \
478 }
479
480 P_FLAG(CLOEXEC);
481 P_FLAG(NONBLOCK);
482#undef P_FLAG
483
484 if (flags)
485 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
486
487 return printed;
488}
489
490#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
491
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300492#if defined(__i386__) || defined(__x86_64__)
493/*
494 * FIXME: Make this available to all arches.
495 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300496#define TCGETS 0x5401
497
498static const char *tioctls[] = {
499 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
500 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
501 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
502 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
503 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
504 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
505 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
506 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
507 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
508 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
509 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
510 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
511 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
512 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
513 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
514};
515
516static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300517#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300518
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300519#ifndef GRND_NONBLOCK
520#define GRND_NONBLOCK 0x0001
521#endif
522#ifndef GRND_RANDOM
523#define GRND_RANDOM 0x0002
524#endif
525
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300526static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
527 struct syscall_arg *arg)
528{
529 int printed = 0, flags = arg->val;
530
531#define P_FLAG(n) \
532 if (flags & GRND_##n) { \
533 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
534 flags &= ~GRND_##n; \
535 }
536
537 P_FLAG(RANDOM);
538 P_FLAG(NONBLOCK);
539#undef P_FLAG
540
541 if (flags)
542 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
543
544 return printed;
545}
546
547#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
548
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300549#define STRARRAY(arg, name, array) \
550 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
551 .arg_parm = { [arg] = &strarray__##array, }
552
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300553#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300554#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300555#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300556#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300557#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300558#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300559#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300560#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300561#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300562#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300563#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300564#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300565#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300566#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300567
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300568static struct syscall_fmt {
569 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300570 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300571 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300572 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300573 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300574 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300575 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300576 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300577} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300578 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300579 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300580 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300581 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300582 { .name = "brk", .hexret = true,
583 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300584 { .name = "chdir", .errmsg = true, },
585 { .name = "chmod", .errmsg = true, },
586 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600587 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300588 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300589 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300590 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300591 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300592 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300593 { .name = "dup", .errmsg = true, },
594 { .name = "dup2", .errmsg = true, },
595 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300596 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300597 { .name = "eventfd2", .errmsg = true,
598 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300599 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300600 { .name = "fadvise64", .errmsg = true, },
601 { .name = "fallocate", .errmsg = true, },
602 { .name = "fchdir", .errmsg = true, },
603 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300604 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300605 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300606 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300607 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300608 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300609 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300610 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300611 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300612 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300613 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300614 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
615 { .name = "fsetxattr", .errmsg = true, },
616 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300617 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300618 { .name = "fstatfs", .errmsg = true, },
619 { .name = "fsync", .errmsg = true, },
620 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300621 { .name = "futex", .errmsg = true,
622 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300623 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300624 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300625 { .name = "getdents", .errmsg = true, },
626 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300627 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300628 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300629 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300630 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300631 { .name = "getrandom", .errmsg = true,
632 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300633 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300634 { .name = "getxattr", .errmsg = true, },
635 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300636 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300637 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300638#if defined(__i386__) || defined(__x86_64__)
639/*
640 * FIXME: Make this available to all arches.
641 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300642 [1] = SCA_STRHEXARRAY, /* cmd */
643 [2] = SCA_HEX, /* arg */ },
644 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300645#else
646 [2] = SCA_HEX, /* arg */ }, },
647#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300648 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300649 { .name = "kill", .errmsg = true,
650 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300651 { .name = "lchown", .errmsg = true, },
652 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300653 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300654 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300655 { .name = "listxattr", .errmsg = true, },
656 { .name = "llistxattr", .errmsg = true, },
657 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300658 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300659 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300660 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300661 { .name = "lsetxattr", .errmsg = true, },
662 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
663 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300664 { .name = "madvise", .errmsg = true,
665 .arg_scnprintf = { [0] = SCA_HEX, /* start */
666 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300667 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300668 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300669 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
670 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300671 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300672 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300673 { .name = "mlock", .errmsg = true,
674 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
675 { .name = "mlockall", .errmsg = true,
676 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300677 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300678 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300679 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300680 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300681 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300682 .arg_scnprintf = { [0] = SCA_HEX, /* start */
683 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300684 { .name = "mq_unlink", .errmsg = true,
685 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300686 { .name = "mremap", .hexret = true,
687 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300688 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300689 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300690 { .name = "munlock", .errmsg = true,
691 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300692 { .name = "munmap", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300694 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300695 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300696 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300697 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300698 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300699 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300700 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300701 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
702 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300703 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300704 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
705 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300706 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300707 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300708 [3] = SCA_FD, /* group_fd */
709 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300710 { .name = "pipe2", .errmsg = true,
711 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300712 { .name = "poll", .errmsg = true, .timeout = true, },
713 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300714 { .name = "pread", .errmsg = true, .alias = "pread64", },
715 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300716 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300717 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
718 { .name = "pwritev", .errmsg = true, },
719 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300720 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300721 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300722 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300723 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300724 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300725 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300726 { .name = "recvmmsg", .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 = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300729 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300730 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300731 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300732 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300733 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300734 { .name = "rt_sigaction", .errmsg = true,
735 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300736 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300737 { .name = "rt_sigqueueinfo", .errmsg = true,
738 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
739 { .name = "rt_tgsigqueueinfo", .errmsg = true,
740 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300741 { .name = "sched_setscheduler", .errmsg = true,
742 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300743 { .name = "seccomp", .errmsg = true,
744 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
745 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300746 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300747 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300748 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300749 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300750 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300751 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300752 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300753 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300754 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300755 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300756 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300757 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300758 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300759 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300760 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
761 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300762 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300763 { .name = "socketpair", .errmsg = true,
764 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
765 [1] = SCA_SK_TYPE, /* type */ },
766 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300767 { .name = "stat", .errmsg = true, .alias = "newstat", },
768 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300769 { .name = "swapoff", .errmsg = true,
770 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
771 { .name = "swapon", .errmsg = true,
772 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300773 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300774 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300775 { .name = "tgkill", .errmsg = true,
776 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
777 { .name = "tkill", .errmsg = true,
778 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300779 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300780 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300781 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300782 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
783 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300784 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300785 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
786 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300787 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300788 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300789 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300790 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300791 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300792 { .name = "write", .errmsg = true, },
793 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300794};
795
796static int syscall_fmt__cmp(const void *name, const void *fmtp)
797{
798 const struct syscall_fmt *fmt = fmtp;
799 return strcmp(name, fmt->name);
800}
801
802static struct syscall_fmt *syscall_fmt__find(const char *name)
803{
804 const int nmemb = ARRAY_SIZE(syscall_fmts);
805 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
806}
807
808struct syscall {
809 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300810 int nr_args;
811 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300812 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300813 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300814 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300815 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300816 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817};
818
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200819static size_t fprintf_duration(unsigned long t, FILE *fp)
820{
821 double duration = (double)t / NSEC_PER_MSEC;
822 size_t printed = fprintf(fp, "(");
823
824 if (duration >= 1.0)
825 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
826 else if (duration >= 0.01)
827 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
828 else
829 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300830 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200831}
832
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300833/**
834 * filename.ptr: The filename char pointer that will be vfs_getname'd
835 * filename.entry_str_pos: Where to insert the string translated from
836 * filename.ptr by the vfs_getname tracepoint/kprobe.
837 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300838struct thread_trace {
839 u64 entry_time;
840 u64 exit_time;
841 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300842 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400843 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300844 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300845 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300846 struct {
847 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300848 short int entry_str_pos;
849 bool pending_open;
850 unsigned int namelen;
851 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300852 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300853 struct {
854 int max;
855 char **table;
856 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600857
858 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300859};
860
861static struct thread_trace *thread_trace__new(void)
862{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300863 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
864
865 if (ttrace)
866 ttrace->paths.max = -1;
867
David Ahernbf2575c2013-10-08 21:26:53 -0600868 ttrace->syscall_stats = intlist__new(NULL);
869
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300870 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300871}
872
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300873static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300874{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300875 struct thread_trace *ttrace;
876
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300877 if (thread == NULL)
878 goto fail;
879
Namhyung Kim89dceb22014-10-06 09:46:03 +0900880 if (thread__priv(thread) == NULL)
881 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300882
Namhyung Kim89dceb22014-10-06 09:46:03 +0900883 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300884 goto fail;
885
Namhyung Kim89dceb22014-10-06 09:46:03 +0900886 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300887 ++ttrace->nr_events;
888
889 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300891 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300892 "WARNING: not enough memory, dropping samples!\n");
893 return NULL;
894}
895
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400896#define TRACE_PFMAJ (1 << 0)
897#define TRACE_PFMIN (1 << 1)
898
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300899static const size_t trace__entry_str_size = 2048;
900
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300901static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300902{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900903 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300904
905 if (fd > ttrace->paths.max) {
906 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
907
908 if (npath == NULL)
909 return -1;
910
911 if (ttrace->paths.max != -1) {
912 memset(npath + ttrace->paths.max + 1, 0,
913 (fd - ttrace->paths.max) * sizeof(char *));
914 } else {
915 memset(npath, 0, (fd + 1) * sizeof(char *));
916 }
917
918 ttrace->paths.table = npath;
919 ttrace->paths.max = fd;
920 }
921
922 ttrace->paths.table[fd] = strdup(pathname);
923
924 return ttrace->paths.table[fd] != NULL ? 0 : -1;
925}
926
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300927static int thread__read_fd_path(struct thread *thread, int fd)
928{
929 char linkname[PATH_MAX], pathname[PATH_MAX];
930 struct stat st;
931 int ret;
932
933 if (thread->pid_ == thread->tid) {
934 scnprintf(linkname, sizeof(linkname),
935 "/proc/%d/fd/%d", thread->pid_, fd);
936 } else {
937 scnprintf(linkname, sizeof(linkname),
938 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
939 }
940
941 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
942 return -1;
943
944 ret = readlink(linkname, pathname, sizeof(pathname));
945
946 if (ret < 0 || ret > st.st_size)
947 return -1;
948
949 pathname[ret] = '\0';
950 return trace__set_fd_pathname(thread, fd, pathname);
951}
952
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300953static const char *thread__fd_path(struct thread *thread, int fd,
954 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300955{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900956 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300957
958 if (ttrace == NULL)
959 return NULL;
960
961 if (fd < 0)
962 return NULL;
963
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300964 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300965 if (!trace->live)
966 return NULL;
967 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300968 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300969 return NULL;
970 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300971
972 return ttrace->paths.table[fd];
973}
974
975static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
976 struct syscall_arg *arg)
977{
978 int fd = arg->val;
979 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300980 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981
982 if (path)
983 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
984
985 return printed;
986}
987
988static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
989 struct syscall_arg *arg)
990{
991 int fd = arg->val;
992 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +0900993 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300995 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
996 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997
998 return printed;
999}
1000
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001001static void thread__set_filename_pos(struct thread *thread, const char *bf,
1002 unsigned long ptr)
1003{
1004 struct thread_trace *ttrace = thread__priv(thread);
1005
1006 ttrace->filename.ptr = ptr;
1007 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1008}
1009
1010static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1011 struct syscall_arg *arg)
1012{
1013 unsigned long ptr = arg->val;
1014
1015 if (!arg->trace->vfs_getname)
1016 return scnprintf(bf, size, "%#x", ptr);
1017
1018 thread__set_filename_pos(arg->thread, bf, ptr);
1019 return 0;
1020}
1021
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001022static bool trace__filter_duration(struct trace *trace, double t)
1023{
1024 return t < (trace->duration_filter * NSEC_PER_MSEC);
1025}
1026
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001027static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1028{
1029 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1030
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001031 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001032}
1033
Namhyung Kimf15eb532012-10-05 14:02:16 +09001034static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001035static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001036
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001037static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001038{
1039 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001040 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001041}
1042
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001043static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001044 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001045{
1046 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001047 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001048
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001049 if (trace->multiple_threads) {
1050 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001051 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001052 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001053 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001054
1055 return printed;
1056}
1057
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001058static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001059 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001060{
1061 int ret = 0;
1062
1063 switch (event->header.type) {
1064 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001065 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001066 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001067 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001068 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001069 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001070 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001071 break;
1072 }
1073
1074 return ret;
1075}
1076
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001077static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001078 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001079 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001080 struct machine *machine)
1081{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001082 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001083 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084}
1085
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001086static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1087{
1088 struct machine *machine = vmachine;
1089
1090 if (machine->kptr_restrict_warned)
1091 return NULL;
1092
1093 if (symbol_conf.kptr_restrict) {
1094 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1095 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1096 "Kernel samples will not be resolved.\n");
1097 machine->kptr_restrict_warned = true;
1098 return NULL;
1099 }
1100
1101 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1102}
1103
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1105{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001106 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107
1108 if (err)
1109 return err;
1110
David Ahern8fb598e2013-09-28 13:13:00 -06001111 trace->host = machine__new_host();
1112 if (trace->host == NULL)
1113 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001114
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001115 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001116 return -errno;
1117
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001118 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001119 evlist->threads, trace__tool_process, false,
1120 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121 if (err)
1122 symbol__exit();
1123
1124 return err;
1125}
1126
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001127static int syscall__set_arg_fmts(struct syscall *sc)
1128{
1129 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001130 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001131
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001132 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001133 if (sc->arg_scnprintf == NULL)
1134 return -1;
1135
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001136 if (sc->fmt)
1137 sc->arg_parm = sc->fmt->arg_parm;
1138
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001139 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001140 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1141 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001142 else if (strcmp(field->type, "const char *") == 0 &&
1143 (strcmp(field->name, "filename") == 0 ||
1144 strcmp(field->name, "path") == 0 ||
1145 strcmp(field->name, "pathname") == 0))
1146 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001147 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001148 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001149 else if (strcmp(field->type, "pid_t") == 0)
1150 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001151 else if (strcmp(field->type, "umode_t") == 0)
1152 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001153 else if ((strcmp(field->type, "int") == 0 ||
1154 strcmp(field->type, "unsigned int") == 0 ||
1155 strcmp(field->type, "long") == 0) &&
1156 (len = strlen(field->name)) >= 2 &&
1157 strcmp(field->name + len - 2, "fd") == 0) {
1158 /*
1159 * /sys/kernel/tracing/events/syscalls/sys_enter*
1160 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1161 * 65 int
1162 * 23 unsigned int
1163 * 7 unsigned long
1164 */
1165 sc->arg_scnprintf[idx] = SCA_FD;
1166 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001167 ++idx;
1168 }
1169
1170 return 0;
1171}
1172
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001173static int trace__read_syscall_info(struct trace *trace, int id)
1174{
1175 char tp_name[128];
1176 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001177 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001178
1179 if (name == NULL)
1180 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001181
1182 if (id > trace->syscalls.max) {
1183 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1184
1185 if (nsyscalls == NULL)
1186 return -1;
1187
1188 if (trace->syscalls.max != -1) {
1189 memset(nsyscalls + trace->syscalls.max + 1, 0,
1190 (id - trace->syscalls.max) * sizeof(*sc));
1191 } else {
1192 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1193 }
1194
1195 trace->syscalls.table = nsyscalls;
1196 trace->syscalls.max = id;
1197 }
1198
1199 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001200 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001201
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001202 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001203
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001204 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001205 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001206
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001207 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001208 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001209 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001210 }
1211
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001212 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001213 return -1;
1214
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001215 sc->args = sc->tp_format->format.fields;
1216 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001217 /*
1218 * We need to check and discard the first variable '__syscall_nr'
1219 * or 'nr' that mean the syscall number. It is needless here.
1220 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1221 */
1222 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001223 sc->args = sc->args->next;
1224 --sc->nr_args;
1225 }
1226
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001227 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1228
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001229 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001230}
1231
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001232static int trace__validate_ev_qualifier(struct trace *trace)
1233{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001234 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001235 struct str_node *pos;
1236
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001237 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1238 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1239 sizeof(trace->ev_qualifier_ids.entries[0]));
1240
1241 if (trace->ev_qualifier_ids.entries == NULL) {
1242 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1243 trace->output);
1244 err = -EINVAL;
1245 goto out;
1246 }
1247
1248 i = 0;
1249
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001250 strlist__for_each(pos, trace->ev_qualifier) {
1251 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001252 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001253
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001254 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001255 if (err == 0) {
1256 fputs("Error:\tInvalid syscall ", trace->output);
1257 err = -EINVAL;
1258 } else {
1259 fputs(", ", trace->output);
1260 }
1261
1262 fputs(sc, trace->output);
1263 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001264
1265 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001266 }
1267
1268 if (err < 0) {
1269 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1270 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001271 zfree(&trace->ev_qualifier_ids.entries);
1272 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001273 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001274out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001275 return err;
1276}
1277
David Ahern55d43bca2015-02-19 15:00:22 -05001278/*
1279 * args is to be interpreted as a series of longs but we need to handle
1280 * 8-byte unaligned accesses. args points to raw_data within the event
1281 * and raw_data is guaranteed to be 8-byte unaligned because it is
1282 * preceded by raw_size which is a u32. So we need to copy args to a temp
1283 * variable to read it. Most notably this avoids extended load instructions
1284 * on unaligned addresses
1285 */
1286
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001287static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001288 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001289 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001290{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001291 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001292 unsigned char *p;
1293 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001294
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001295 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001296 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001297 u8 bit = 1;
1298 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001299 .idx = 0,
1300 .mask = 0,
1301 .trace = trace,
1302 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001303 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001304
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001305 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001306 field = field->next, ++arg.idx, bit <<= 1) {
1307 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001308 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001309
1310 /* special care for unaligned accesses */
1311 p = args + sizeof(unsigned long) * arg.idx;
1312 memcpy(&val, p, sizeof(val));
1313
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001314 /*
1315 * Suppress this argument if its value is zero and
1316 * and we don't have a string associated in an
1317 * strarray for it.
1318 */
David Ahern55d43bca2015-02-19 15:00:22 -05001319 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001320 !(sc->arg_scnprintf &&
1321 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1322 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001323 continue;
1324
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001325 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001326 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001327 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001328 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001329 if (sc->arg_parm)
1330 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001331 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1332 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001333 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001334 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001335 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001336 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001337 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001338 } else if (IS_ERR(sc->tp_format)) {
1339 /*
1340 * If we managed to read the tracepoint /format file, then we
1341 * may end up not having any args, like with gettid(), so only
1342 * print the raw args when we didn't manage to read it.
1343 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001344 int i = 0;
1345
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001346 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001347 /* special care for unaligned accesses */
1348 p = args + sizeof(unsigned long) * i;
1349 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001350 printed += scnprintf(bf + printed, size - printed,
1351 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001352 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001353 ++i;
1354 }
1355 }
1356
1357 return printed;
1358}
1359
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001360typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001361 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001362 struct perf_sample *sample);
1363
1364static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001365 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001366{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001367
1368 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001369
1370 /*
1371 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1372 * before that, leaving at a higher verbosity level till that is
1373 * explained. Reproduced with plain ftrace with:
1374 *
1375 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1376 * grep "NR -1 " /t/trace_pipe
1377 *
1378 * After generating some load on the machine.
1379 */
1380 if (verbose > 1) {
1381 static u64 n;
1382 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1383 id, perf_evsel__name(evsel), ++n);
1384 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001385 return NULL;
1386 }
1387
1388 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1389 trace__read_syscall_info(trace, id))
1390 goto out_cant_read;
1391
1392 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1393 goto out_cant_read;
1394
1395 return &trace->syscalls.table[id];
1396
1397out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001398 if (verbose) {
1399 fprintf(trace->output, "Problems reading syscall %d", id);
1400 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1401 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1402 fputs(" information\n", trace->output);
1403 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001404 return NULL;
1405}
1406
David Ahernbf2575c2013-10-08 21:26:53 -06001407static void thread__update_stats(struct thread_trace *ttrace,
1408 int id, struct perf_sample *sample)
1409{
1410 struct int_node *inode;
1411 struct stats *stats;
1412 u64 duration = 0;
1413
1414 inode = intlist__findnew(ttrace->syscall_stats, id);
1415 if (inode == NULL)
1416 return;
1417
1418 stats = inode->priv;
1419 if (stats == NULL) {
1420 stats = malloc(sizeof(struct stats));
1421 if (stats == NULL)
1422 return;
1423 init_stats(stats);
1424 inode->priv = stats;
1425 }
1426
1427 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1428 duration = sample->time - ttrace->entry_time;
1429
1430 update_stats(stats, duration);
1431}
1432
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001433static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1434{
1435 struct thread_trace *ttrace;
1436 u64 duration;
1437 size_t printed;
1438
1439 if (trace->current == NULL)
1440 return 0;
1441
1442 ttrace = thread__priv(trace->current);
1443
1444 if (!ttrace->entry_pending)
1445 return 0;
1446
1447 duration = sample->time - ttrace->entry_time;
1448
1449 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1450 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1451 ttrace->entry_pending = false;
1452
1453 return printed;
1454}
1455
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001456static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001457 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001458 struct perf_sample *sample)
1459{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001460 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001461 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001462 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001463 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001464 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001465 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001466 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001467
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001468 if (sc == NULL)
1469 return -1;
1470
David Ahern8fb598e2013-09-28 13:13:00 -06001471 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001472 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001473 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001474 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001475
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001476 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001477
1478 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001479 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001481 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001482 }
1483
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001484 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001485 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001486
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487 ttrace->entry_time = sample->time;
1488 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001489 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001490
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001491 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001492 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001493
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001494 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001495 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001496 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001497 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001498 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001499 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001500 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001501 /* See trace__vfs_getname & trace__sys_exit */
1502 ttrace->filename.pending_open = false;
1503 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001504
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001505 if (trace->current != thread) {
1506 thread__put(trace->current);
1507 trace->current = thread__get(thread);
1508 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001509 err = 0;
1510out_put:
1511 thread__put(thread);
1512 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001513}
1514
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001515static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1516 struct perf_sample *sample,
1517 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001518{
1519 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001520
1521 if (machine__resolve(trace->host, &al, sample) < 0 ||
1522 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1523 return -1;
1524
1525 return 0;
1526}
1527
1528static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1529{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001530 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001531 const unsigned int print_opts = EVSEL__PRINT_SYM |
1532 EVSEL__PRINT_DSO |
1533 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001534
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001535 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001536}
1537
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001538static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001539 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001540 struct perf_sample *sample)
1541{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001542 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001543 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001544 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001545 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001546 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001547 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001548
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001549 if (sc == NULL)
1550 return -1;
1551
David Ahern8fb598e2013-09-28 13:13:00 -06001552 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001553 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001554 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001555 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001556
David Ahernbf2575c2013-10-08 21:26:53 -06001557 if (trace->summary)
1558 thread__update_stats(ttrace, id, sample);
1559
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001560 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001561
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001562 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001563 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1564 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001565 ++trace->stats.vfs_getname;
1566 }
1567
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001568 ttrace->exit_time = sample->time;
1569
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001570 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001571 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001572 if (trace__filter_duration(trace, duration))
1573 goto out;
1574 } else if (trace->duration_filter)
1575 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001576
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001577 if (sample->callchain) {
1578 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1579 if (callchain_ret == 0) {
1580 if (callchain_cursor.nr < trace->min_stack)
1581 goto out;
1582 callchain_ret = 1;
1583 }
1584 }
1585
David Ahernfd2eaba2013-11-12 09:31:15 -07001586 if (trace->summary_only)
1587 goto out;
1588
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001589 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001590
1591 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001592 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001593 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001594 fprintf(trace->output, " ... [");
1595 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1596 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001597 }
1598
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001599 if (sc->fmt == NULL) {
1600signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001601 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001602 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001603 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001604 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1605 *e = audit_errno_to_name(-ret);
1606
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001607 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001608 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001609 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001610 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001611 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001612 else if (sc->fmt->errpid) {
1613 struct thread *child = machine__find_thread(trace->host, ret, ret);
1614
1615 if (child != NULL) {
1616 fprintf(trace->output, ") = %ld", ret);
1617 if (child->comm_set)
1618 fprintf(trace->output, " (%s)", thread__comm_str(child));
1619 thread__put(child);
1620 }
1621 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001622 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001623
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001624 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001625
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001626 if (callchain_ret > 0)
1627 trace__fprintf_callchain(trace, sample);
1628 else if (callchain_ret < 0)
1629 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001630out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001631 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001632 err = 0;
1633out_put:
1634 thread__put(thread);
1635 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001636}
1637
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001638static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001639 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001640 struct perf_sample *sample)
1641{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001642 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1643 struct thread_trace *ttrace;
1644 size_t filename_len, entry_str_len, to_move;
1645 ssize_t remaining_space;
1646 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001647 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001648
1649 if (!thread)
1650 goto out;
1651
1652 ttrace = thread__priv(thread);
1653 if (!ttrace)
1654 goto out;
1655
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001656 filename_len = strlen(filename);
1657
1658 if (ttrace->filename.namelen < filename_len) {
1659 char *f = realloc(ttrace->filename.name, filename_len + 1);
1660
1661 if (f == NULL)
1662 goto out;
1663
1664 ttrace->filename.namelen = filename_len;
1665 ttrace->filename.name = f;
1666 }
1667
1668 strcpy(ttrace->filename.name, filename);
1669 ttrace->filename.pending_open = true;
1670
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001671 if (!ttrace->filename.ptr)
1672 goto out;
1673
1674 entry_str_len = strlen(ttrace->entry_str);
1675 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1676 if (remaining_space <= 0)
1677 goto out;
1678
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001679 if (filename_len > (size_t)remaining_space) {
1680 filename += filename_len - remaining_space;
1681 filename_len = remaining_space;
1682 }
1683
1684 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1685 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1686 memmove(pos + filename_len, pos, to_move);
1687 memcpy(pos, filename, filename_len);
1688
1689 ttrace->filename.ptr = 0;
1690 ttrace->filename.entry_str_pos = 0;
1691out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001692 return 0;
1693}
1694
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001695static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001696 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001697 struct perf_sample *sample)
1698{
1699 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1700 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001701 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001702 sample->pid,
1703 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001704 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001705
1706 if (ttrace == NULL)
1707 goto out_dump;
1708
1709 ttrace->runtime_ms += runtime_ms;
1710 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001711 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001712 return 0;
1713
1714out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001715 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001716 evsel->name,
1717 perf_evsel__strval(evsel, sample, "comm"),
1718 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1719 runtime,
1720 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001721 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001722 return 0;
1723}
1724
Wang Nan1d6c9402016-02-26 09:31:55 +00001725static void bpf_output__printer(enum binary_printer_ops op,
1726 unsigned int val, void *extra)
1727{
1728 FILE *output = extra;
1729 unsigned char ch = (unsigned char)val;
1730
1731 switch (op) {
1732 case BINARY_PRINT_CHAR_DATA:
1733 fprintf(output, "%c", isprint(ch) ? ch : '.');
1734 break;
1735 case BINARY_PRINT_DATA_BEGIN:
1736 case BINARY_PRINT_LINE_BEGIN:
1737 case BINARY_PRINT_ADDR:
1738 case BINARY_PRINT_NUM_DATA:
1739 case BINARY_PRINT_NUM_PAD:
1740 case BINARY_PRINT_SEP:
1741 case BINARY_PRINT_CHAR_PAD:
1742 case BINARY_PRINT_LINE_END:
1743 case BINARY_PRINT_DATA_END:
1744 default:
1745 break;
1746 }
1747}
1748
1749static void bpf_output__fprintf(struct trace *trace,
1750 struct perf_sample *sample)
1751{
1752 print_binary(sample->raw_data, sample->raw_size, 8,
1753 bpf_output__printer, trace->output);
1754}
1755
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001756static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1757 union perf_event *event __maybe_unused,
1758 struct perf_sample *sample)
1759{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001760 int callchain_ret = 0;
1761
1762 if (sample->callchain) {
1763 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1764 if (callchain_ret == 0) {
1765 if (callchain_cursor.nr < trace->min_stack)
1766 goto out;
1767 callchain_ret = 1;
1768 }
1769 }
1770
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001771 trace__printf_interrupted_entry(trace, sample);
1772 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001773
1774 if (trace->trace_syscalls)
1775 fprintf(trace->output, "( ): ");
1776
1777 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001778
Wang Nan1d6c9402016-02-26 09:31:55 +00001779 if (perf_evsel__is_bpf_output(evsel)) {
1780 bpf_output__fprintf(trace, sample);
1781 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001782 event_format__fprintf(evsel->tp_format, sample->cpu,
1783 sample->raw_data, sample->raw_size,
1784 trace->output);
1785 }
1786
1787 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001788
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001789 if (callchain_ret > 0)
1790 trace__fprintf_callchain(trace, sample);
1791 else if (callchain_ret < 0)
1792 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1793out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001794 return 0;
1795}
1796
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001797static void print_location(FILE *f, struct perf_sample *sample,
1798 struct addr_location *al,
1799 bool print_dso, bool print_sym)
1800{
1801
1802 if ((verbose || print_dso) && al->map)
1803 fprintf(f, "%s@", al->map->dso->long_name);
1804
1805 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001806 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001807 al->addr - al->sym->start);
1808 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001809 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001810 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001811 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001812}
1813
1814static int trace__pgfault(struct trace *trace,
1815 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001816 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001817 struct perf_sample *sample)
1818{
1819 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001820 struct addr_location al;
1821 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001822 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001823 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001824 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001825
1826 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001827
1828 if (sample->callchain) {
1829 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1830 if (callchain_ret == 0) {
1831 if (callchain_cursor.nr < trace->min_stack)
1832 goto out_put;
1833 callchain_ret = 1;
1834 }
1835 }
1836
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001837 ttrace = thread__trace(thread, trace->output);
1838 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001839 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001840
1841 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1842 ttrace->pfmaj++;
1843 else
1844 ttrace->pfmin++;
1845
1846 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001847 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001848
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001849 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001850 sample->ip, &al);
1851
1852 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1853
1854 fprintf(trace->output, "%sfault [",
1855 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1856 "maj" : "min");
1857
1858 print_location(trace->output, sample, &al, false, true);
1859
1860 fprintf(trace->output, "] => ");
1861
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001862 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001863 sample->addr, &al);
1864
1865 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001866 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001867 MAP__FUNCTION, sample->addr, &al);
1868
1869 if (al.map)
1870 map_type = 'x';
1871 else
1872 map_type = '?';
1873 }
1874
1875 print_location(trace->output, sample, &al, true, false);
1876
1877 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001878
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001879 if (callchain_ret > 0)
1880 trace__fprintf_callchain(trace, sample);
1881 else if (callchain_ret < 0)
1882 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001883out:
1884 err = 0;
1885out_put:
1886 thread__put(thread);
1887 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888}
1889
David Ahernbdc89662013-08-28 22:29:53 -06001890static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1891{
1892 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1893 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1894 return false;
1895
1896 if (trace->pid_list || trace->tid_list)
1897 return true;
1898
1899 return false;
1900}
1901
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001902static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001903 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001904 struct perf_sample *sample)
1905{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001906 /*
1907 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1908 * and don't use sample->time unconditionally, we may end up having
1909 * some other event in the future without PERF_SAMPLE_TIME for good
1910 * reason, i.e. we may not be interested in its timestamps, just in
1911 * it taking place, picking some piece of information when it
1912 * appears in our event stream (vfs_getname comes to mind).
1913 */
1914 if (trace->base_time == 0 && !trace->full_time &&
1915 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001916 trace->base_time = sample->time;
1917}
1918
David Ahern6810fc92013-08-28 22:29:52 -06001919static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001920 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001921 struct perf_sample *sample,
1922 struct perf_evsel *evsel,
1923 struct machine *machine __maybe_unused)
1924{
1925 struct trace *trace = container_of(tool, struct trace, tool);
1926 int err = 0;
1927
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001928 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001929
David Ahernbdc89662013-08-28 22:29:53 -06001930 if (skip_sample(trace, sample))
1931 return 0;
1932
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001933 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001934
David Ahern31605652013-12-04 19:41:41 -07001935 if (handler) {
1936 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001937 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001938 }
David Ahern6810fc92013-08-28 22:29:52 -06001939
1940 return err;
1941}
1942
David Ahernbdc89662013-08-28 22:29:53 -06001943static int parse_target_str(struct trace *trace)
1944{
1945 if (trace->opts.target.pid) {
1946 trace->pid_list = intlist__new(trace->opts.target.pid);
1947 if (trace->pid_list == NULL) {
1948 pr_err("Error parsing process id string\n");
1949 return -EINVAL;
1950 }
1951 }
1952
1953 if (trace->opts.target.tid) {
1954 trace->tid_list = intlist__new(trace->opts.target.tid);
1955 if (trace->tid_list == NULL) {
1956 pr_err("Error parsing thread id string\n");
1957 return -EINVAL;
1958 }
1959 }
1960
1961 return 0;
1962}
1963
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001964static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001965{
1966 unsigned int rec_argc, i, j;
1967 const char **rec_argv;
1968 const char * const record_args[] = {
1969 "record",
1970 "-R",
1971 "-m", "1024",
1972 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001973 };
1974
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001975 const char * const sc_args[] = { "-e", };
1976 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1977 const char * const majpf_args[] = { "-e", "major-faults" };
1978 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1979 const char * const minpf_args[] = { "-e", "minor-faults" };
1980 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1981
David Ahern9aca7f12013-12-04 19:41:39 -07001982 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001983 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1984 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001985 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1986
1987 if (rec_argv == NULL)
1988 return -ENOMEM;
1989
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001990 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001991 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001992 rec_argv[j++] = record_args[i];
1993
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001994 if (trace->trace_syscalls) {
1995 for (i = 0; i < sc_args_nr; i++)
1996 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001997
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001998 /* event string may be different for older kernels - e.g., RHEL6 */
1999 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2000 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2001 else if (is_valid_tracepoint("syscalls:sys_enter"))
2002 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2003 else {
2004 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2005 return -1;
2006 }
David Ahern9aca7f12013-12-04 19:41:39 -07002007 }
David Ahern9aca7f12013-12-04 19:41:39 -07002008
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002009 if (trace->trace_pgfaults & TRACE_PFMAJ)
2010 for (i = 0; i < majpf_args_nr; i++)
2011 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002012
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002013 if (trace->trace_pgfaults & TRACE_PFMIN)
2014 for (i = 0; i < minpf_args_nr; i++)
2015 rec_argv[j++] = minpf_args[i];
2016
2017 for (i = 0; i < (unsigned int)argc; i++)
2018 rec_argv[j++] = argv[i];
2019
2020 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002021}
2022
David Ahernbf2575c2013-10-08 21:26:53 -06002023static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2024
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002025static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002026{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002027 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002028
2029 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002030 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002031
2032 if (perf_evsel__field(evsel, "pathname") == NULL) {
2033 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002034 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002035 }
2036
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002037 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002038 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002039 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002040}
2041
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002042static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002043{
2044 struct perf_evsel *evsel;
2045 struct perf_event_attr attr = {
2046 .type = PERF_TYPE_SOFTWARE,
2047 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002048 };
2049
2050 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002051 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002052
2053 event_attr_init(&attr);
2054
2055 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002056 if (evsel)
2057 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002058
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002059 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002060}
2061
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002062static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2063{
2064 const u32 type = event->header.type;
2065 struct perf_evsel *evsel;
2066
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002067 if (type != PERF_RECORD_SAMPLE) {
2068 trace__process_event(trace, trace->host, event, sample);
2069 return;
2070 }
2071
2072 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2073 if (evsel == NULL) {
2074 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2075 return;
2076 }
2077
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002078 trace__set_base_time(trace, evsel, sample);
2079
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002080 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2081 sample->raw_data == NULL) {
2082 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2083 perf_evsel__name(evsel), sample->tid,
2084 sample->cpu, sample->raw_size);
2085 } else {
2086 tracepoint_handler handler = evsel->handler;
2087 handler(trace, evsel, event, sample);
2088 }
2089}
2090
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002091static int trace__add_syscall_newtp(struct trace *trace)
2092{
2093 int ret = -1;
2094 struct perf_evlist *evlist = trace->evlist;
2095 struct perf_evsel *sys_enter, *sys_exit;
2096
2097 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2098 if (sys_enter == NULL)
2099 goto out;
2100
2101 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2102 goto out_delete_sys_enter;
2103
2104 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2105 if (sys_exit == NULL)
2106 goto out_delete_sys_enter;
2107
2108 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2109 goto out_delete_sys_exit;
2110
2111 perf_evlist__add(evlist, sys_enter);
2112 perf_evlist__add(evlist, sys_exit);
2113
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002114 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002115 /*
2116 * We're interested only in the user space callchain
2117 * leading to the syscall, allow overriding that for
2118 * debugging reasons using --kernel_syscall_callchains
2119 */
2120 sys_exit->attr.exclude_callchain_kernel = 1;
2121 }
2122
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002123 trace->syscalls.events.sys_enter = sys_enter;
2124 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002125
2126 ret = 0;
2127out:
2128 return ret;
2129
2130out_delete_sys_exit:
2131 perf_evsel__delete_priv(sys_exit);
2132out_delete_sys_enter:
2133 perf_evsel__delete_priv(sys_enter);
2134 goto out;
2135}
2136
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002137static int trace__set_ev_qualifier_filter(struct trace *trace)
2138{
2139 int err = -1;
2140 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2141 trace->ev_qualifier_ids.nr,
2142 trace->ev_qualifier_ids.entries);
2143
2144 if (filter == NULL)
2145 goto out_enomem;
2146
2147 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2148 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2149
2150 free(filter);
2151out:
2152 return err;
2153out_enomem:
2154 errno = ENOMEM;
2155 goto out;
2156}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002157
Namhyung Kimf15eb532012-10-05 14:02:16 +09002158static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002159{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002160 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002161 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002162 int err = -1, i;
2163 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002164 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002165 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002166
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002167 trace->live = true;
2168
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002169 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002170 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002171
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002172 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002173 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002174
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002175 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2176 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2177 if (pgfault_maj == NULL)
2178 goto out_error_mem;
2179 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002180 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002181
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002182 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2183 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2184 if (pgfault_min == NULL)
2185 goto out_error_mem;
2186 perf_evlist__add(evlist, pgfault_min);
2187 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002188
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002189 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002190 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2191 trace__sched_stat_runtime))
2192 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002193
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002194 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2195 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002196 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002197 goto out_delete_evlist;
2198 }
2199
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002200 err = trace__symbols_init(trace, evlist);
2201 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002202 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002203 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002204 }
2205
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002206 perf_evlist__config(evlist, &trace->opts, NULL);
2207
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002208 if (callchain_param.enabled) {
2209 bool use_identifier = false;
2210
2211 if (trace->syscalls.events.sys_exit) {
2212 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2213 &trace->opts, &callchain_param);
2214 use_identifier = true;
2215 }
2216
2217 if (pgfault_maj) {
2218 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2219 use_identifier = true;
2220 }
2221
2222 if (pgfault_min) {
2223 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2224 use_identifier = true;
2225 }
2226
2227 if (use_identifier) {
2228 /*
2229 * Now we have evsels with different sample_ids, use
2230 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2231 * from a fixed position in each ring buffer record.
2232 *
2233 * As of this the changeset introducing this comment, this
2234 * isn't strictly needed, as the fields that can come before
2235 * PERF_SAMPLE_ID are all used, but we'll probably disable
2236 * some of those for things like copying the payload of
2237 * pointer syscall arguments, and for vfs_getname we don't
2238 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2239 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2240 */
2241 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2242 perf_evlist__reset_sample_bit(evlist, ID);
2243 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002244 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002245
Namhyung Kimf15eb532012-10-05 14:02:16 +09002246 signal(SIGCHLD, sig_handler);
2247 signal(SIGINT, sig_handler);
2248
2249 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002250 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002251 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002252 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002253 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002254 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002255 }
2256 }
2257
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002258 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002259 if (err < 0)
2260 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261
Wang Nanba504232016-02-26 09:31:54 +00002262 err = bpf__apply_obj_config();
2263 if (err) {
2264 char errbuf[BUFSIZ];
2265
2266 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2267 pr_err("ERROR: Apply config to BPF failed: %s\n",
2268 errbuf);
2269 goto out_error_open;
2270 }
2271
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002272 /*
2273 * Better not use !target__has_task() here because we need to cover the
2274 * case where no threads were specified in the command line, but a
2275 * workload was, and in that case we will fill in the thread_map when
2276 * we fork the workload in perf_evlist__prepare_workload.
2277 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002278 if (trace->filter_pids.nr > 0)
2279 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002280 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002281 err = perf_evlist__set_filter_pid(evlist, getpid());
2282
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002283 if (err < 0)
2284 goto out_error_mem;
2285
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002286 if (trace->ev_qualifier_ids.nr > 0) {
2287 err = trace__set_ev_qualifier_filter(trace);
2288 if (err < 0)
2289 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002290
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002291 pr_debug("event qualifier tracepoint filter: %s\n",
2292 trace->syscalls.events.sys_exit->filter);
2293 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002294
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002295 err = perf_evlist__apply_filters(evlist, &evsel);
2296 if (err < 0)
2297 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002298
Jiri Olsaf8850372013-11-28 17:57:22 +01002299 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002300 if (err < 0)
2301 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002302
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002303 if (!target__none(&trace->opts.target))
2304 perf_evlist__enable(evlist);
2305
Namhyung Kimf15eb532012-10-05 14:02:16 +09002306 if (forks)
2307 perf_evlist__start_workload(evlist);
2308
Jiri Olsae13798c2015-06-23 00:36:02 +02002309 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002310 evlist->threads->nr > 1 ||
2311 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002312again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002313 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002314
2315 for (i = 0; i < evlist->nr_mmaps; i++) {
2316 union perf_event *event;
2317
2318 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002319 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002320
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002321 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002323 err = perf_evlist__parse_sample(evlist, event, &sample);
2324 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002325 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002326 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002327 }
2328
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002329 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002330next_event:
2331 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002332
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002333 if (interrupted)
2334 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002335
2336 if (done && !draining) {
2337 perf_evlist__disable(evlist);
2338 draining = true;
2339 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002340 }
2341 }
2342
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002343 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002344 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002345
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002346 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2347 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2348 draining = true;
2349
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002350 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002351 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002352 } else {
2353 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002354 }
2355
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002356out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002357 thread__zput(trace->current);
2358
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002359 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002360
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002361 if (!err) {
2362 if (trace->summary)
2363 trace__fprintf_thread_summary(trace, trace->output);
2364
2365 if (trace->show_tool_stats) {
2366 fprintf(trace->output, "Stats:\n "
2367 " vfs_getname : %" PRIu64 "\n"
2368 " proc_getname: %" PRIu64 "\n",
2369 trace->stats.vfs_getname,
2370 trace->stats.proc_getname);
2371 }
2372 }
David Ahernbf2575c2013-10-08 21:26:53 -06002373
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002374out_delete_evlist:
2375 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002376 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002377 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002378 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002379{
2380 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002381
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002382out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002383 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002384 goto out_error;
2385
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002386out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002387 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002388 goto out_error;
2389
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002390out_error_mmap:
2391 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2392 goto out_error;
2393
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002394out_error_open:
2395 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2396
2397out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002398 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302399 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002400
2401out_error_apply_filters:
2402 fprintf(trace->output,
2403 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2404 evsel->filter, perf_evsel__name(evsel), errno,
2405 strerror_r(errno, errbuf, sizeof(errbuf)));
2406 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002407}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002408out_error_mem:
2409 fprintf(trace->output, "Not enough memory to run!\n");
2410 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002411
2412out_errno:
2413 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2414 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002415}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002416
David Ahern6810fc92013-08-28 22:29:52 -06002417static int trace__replay(struct trace *trace)
2418{
2419 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002420 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002421 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002422 struct perf_data_file file = {
2423 .path = input_name,
2424 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002425 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002426 };
David Ahern6810fc92013-08-28 22:29:52 -06002427 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002428 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002429 int err = -1;
2430
2431 trace->tool.sample = trace__process_sample;
2432 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002433 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002434 trace->tool.comm = perf_event__process_comm;
2435 trace->tool.exit = perf_event__process_exit;
2436 trace->tool.fork = perf_event__process_fork;
2437 trace->tool.attr = perf_event__process_attr;
2438 trace->tool.tracing_data = perf_event__process_tracing_data;
2439 trace->tool.build_id = perf_event__process_build_id;
2440
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002441 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002442 trace->tool.ordering_requires_timestamps = true;
2443
2444 /* add tid to output */
2445 trace->multiple_threads = true;
2446
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002447 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002448 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002449 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002450
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002451 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002452 goto out;
2453
David Ahern8fb598e2013-09-28 13:13:00 -06002454 trace->host = &session->machines.host;
2455
David Ahern6810fc92013-08-28 22:29:52 -06002456 err = perf_session__set_tracepoints_handlers(session, handlers);
2457 if (err)
2458 goto out;
2459
Namhyung Kim003824e2013-11-12 15:25:00 +09002460 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2461 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002462 /* older kernels have syscalls tp versus raw_syscalls */
2463 if (evsel == NULL)
2464 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2465 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002466
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002467 if (evsel &&
2468 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2469 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002470 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2471 goto out;
2472 }
2473
2474 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2475 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002476 if (evsel == NULL)
2477 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2478 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002479 if (evsel &&
2480 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2481 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002482 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002483 goto out;
2484 }
2485
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002486 evlist__for_each(session->evlist, evsel) {
2487 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2488 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2489 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2490 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2491 evsel->handler = trace__pgfault;
2492 }
2493
David Ahernbdc89662013-08-28 22:29:53 -06002494 err = parse_target_str(trace);
2495 if (err != 0)
2496 goto out;
2497
David Ahern6810fc92013-08-28 22:29:52 -06002498 setup_pager();
2499
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002500 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002501 if (err)
2502 pr_err("Failed to process events, error %d", err);
2503
David Ahernbf2575c2013-10-08 21:26:53 -06002504 else if (trace->summary)
2505 trace__fprintf_thread_summary(trace, trace->output);
2506
David Ahern6810fc92013-08-28 22:29:52 -06002507out:
2508 perf_session__delete(session);
2509
2510 return err;
2511}
2512
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002513static size_t trace__fprintf_threads_header(FILE *fp)
2514{
2515 size_t printed;
2516
Pekka Enberg99ff7152013-11-12 16:42:14 +02002517 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002518
2519 return printed;
2520}
2521
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002522DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2523 struct stats *stats;
2524 double msecs;
2525 int syscall;
2526)
2527{
2528 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2529 struct stats *stats = source->priv;
2530
2531 entry->syscall = source->i;
2532 entry->stats = stats;
2533 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2534}
2535
David Ahernbf2575c2013-10-08 21:26:53 -06002536static size_t thread__dump_stats(struct thread_trace *ttrace,
2537 struct trace *trace, FILE *fp)
2538{
David Ahernbf2575c2013-10-08 21:26:53 -06002539 size_t printed = 0;
2540 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002541 struct rb_node *nd;
2542 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002543
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002544 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002545 return 0;
2546
2547 printed += fprintf(fp, "\n");
2548
Milian Wolff834fd462015-08-06 11:24:29 +02002549 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2550 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2551 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002552
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002553 resort_rb__for_each(nd, syscall_stats) {
2554 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002555 if (stats) {
2556 double min = (double)(stats->min) / NSEC_PER_MSEC;
2557 double max = (double)(stats->max) / NSEC_PER_MSEC;
2558 double avg = avg_stats(stats);
2559 double pct;
2560 u64 n = (u64) stats->n;
2561
2562 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2563 avg /= NSEC_PER_MSEC;
2564
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002565 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002566 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002567 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002568 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002569 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002570 }
David Ahernbf2575c2013-10-08 21:26:53 -06002571 }
2572
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002573 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002574 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002575
2576 return printed;
2577}
2578
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002579static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002580{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002581 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002582 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002583 double ratio;
2584
2585 if (ttrace == NULL)
2586 return 0;
2587
2588 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2589
Pekka Enberg15e65c62013-11-14 18:43:30 +02002590 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002591 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002592 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002593 if (ttrace->pfmaj)
2594 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2595 if (ttrace->pfmin)
2596 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002597 if (trace->sched)
2598 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2599 else if (fputc('\n', fp) != EOF)
2600 ++printed;
2601
David Ahernbf2575c2013-10-08 21:26:53 -06002602 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002603
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002604 return printed;
2605}
David Ahern896cbb52013-09-28 13:12:59 -06002606
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002607static unsigned long thread__nr_events(struct thread_trace *ttrace)
2608{
2609 return ttrace ? ttrace->nr_events : 0;
2610}
2611
2612DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2613 struct thread *thread;
2614)
2615{
2616 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002617}
2618
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002619static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2620{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002621 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2622 size_t printed = trace__fprintf_threads_header(fp);
2623 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002624
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002625 if (threads == NULL) {
2626 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2627 return 0;
2628 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002629
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002630 resort_rb__for_each(nd, threads)
2631 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2632
2633 resort_rb__delete(threads);
2634
2635 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002636}
2637
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002638static int trace__set_duration(const struct option *opt, const char *str,
2639 int unset __maybe_unused)
2640{
2641 struct trace *trace = opt->value;
2642
2643 trace->duration_filter = atof(str);
2644 return 0;
2645}
2646
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002647static int trace__set_filter_pids(const struct option *opt, const char *str,
2648 int unset __maybe_unused)
2649{
2650 int ret = -1;
2651 size_t i;
2652 struct trace *trace = opt->value;
2653 /*
2654 * FIXME: introduce a intarray class, plain parse csv and create a
2655 * { int nr, int entries[] } struct...
2656 */
2657 struct intlist *list = intlist__new(str);
2658
2659 if (list == NULL)
2660 return -1;
2661
2662 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2663 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2664
2665 if (trace->filter_pids.entries == NULL)
2666 goto out;
2667
2668 trace->filter_pids.entries[0] = getpid();
2669
2670 for (i = 1; i < trace->filter_pids.nr; ++i)
2671 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2672
2673 intlist__delete(list);
2674 ret = 0;
2675out:
2676 return ret;
2677}
2678
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002679static int trace__open_output(struct trace *trace, const char *filename)
2680{
2681 struct stat st;
2682
2683 if (!stat(filename, &st) && st.st_size) {
2684 char oldname[PATH_MAX];
2685
2686 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2687 unlink(oldname);
2688 rename(filename, oldname);
2689 }
2690
2691 trace->output = fopen(filename, "w");
2692
2693 return trace->output == NULL ? -errno : 0;
2694}
2695
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002696static int parse_pagefaults(const struct option *opt, const char *str,
2697 int unset __maybe_unused)
2698{
2699 int *trace_pgfaults = opt->value;
2700
2701 if (strcmp(str, "all") == 0)
2702 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2703 else if (strcmp(str, "maj") == 0)
2704 *trace_pgfaults |= TRACE_PFMAJ;
2705 else if (strcmp(str, "min") == 0)
2706 *trace_pgfaults |= TRACE_PFMIN;
2707 else
2708 return -1;
2709
2710 return 0;
2711}
2712
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002713static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2714{
2715 struct perf_evsel *evsel;
2716
2717 evlist__for_each(evlist, evsel)
2718 evsel->handler = handler;
2719}
2720
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002721int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2722{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002723 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002724 "perf trace [<options>] [<command>]",
2725 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002726 "perf trace record [<options>] [<command>]",
2727 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002728 NULL
2729 };
2730 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002731 .syscalls = {
2732 . max = -1,
2733 },
2734 .opts = {
2735 .target = {
2736 .uid = UINT_MAX,
2737 .uses_mmap = true,
2738 },
2739 .user_freq = UINT_MAX,
2740 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002741 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002742 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002743 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002744 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002745 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002746 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002747 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002748 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002749 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002750 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002751 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002752 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002753 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002754 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2755 "event selector. use 'perf list' to list available events",
2756 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002757 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2758 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002759 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002760 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002761 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002762 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002763 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2764 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002765 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002766 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002767 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2768 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002769 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002770 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002771 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002772 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002773 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002774 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002775 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2776 "number of mmap data pages",
2777 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002778 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002779 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002780 OPT_CALLBACK(0, "duration", &trace, "float",
2781 "show only events with duration > N.M ms",
2782 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002783 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002784 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002785 OPT_BOOLEAN('T', "time", &trace.full_time,
2786 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002787 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2788 "Show only syscall summary with statistics"),
2789 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2790 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002791 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2792 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002793 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002794 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002795 OPT_CALLBACK(0, "call-graph", &trace.opts,
2796 "record_mode[,record_size]", record_callchain_help,
2797 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002798 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2799 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002800 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2801 "Set the minimum stack depth when parsing the callchain, "
2802 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002803 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2804 "Set the maximum stack depth when parsing the callchain, "
2805 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002806 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002807 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2808 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002809 OPT_END()
2810 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002811 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002812 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002813 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002814 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002815 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002816
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002817 signal(SIGSEGV, sighandler_dump_stack);
2818 signal(SIGFPE, sighandler_dump_stack);
2819
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002820 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002821 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002822
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002823 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002824 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002825 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002826 goto out;
2827 }
2828
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002829 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2830 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002831
Wang Nand7888572016-04-08 15:07:24 +00002832 err = bpf__setup_stdout(trace.evlist);
2833 if (err) {
2834 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2835 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2836 goto out;
2837 }
2838
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002839 err = -1;
2840
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002841 if (trace.trace_pgfaults) {
2842 trace.opts.sample_address = true;
2843 trace.opts.sample_time = true;
2844 }
2845
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002846 if (trace.opts.mmap_pages == UINT_MAX)
2847 mmap_pages_user_set = false;
2848
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002849 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002850 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002851 max_stack_user_set = false;
2852 }
2853
2854#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002855 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002856 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2857#endif
2858
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002859 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002860 if (!mmap_pages_user_set && geteuid() == 0)
2861 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2862
Milian Wolff566a0882016-04-08 13:34:15 +02002863 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002864 }
Milian Wolff566a0882016-04-08 13:34:15 +02002865
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002866 if (trace.evlist->nr_entries > 0)
2867 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2868
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002869 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2870 return trace__record(&trace, argc-1, &argv[1]);
2871
2872 /* summary_only implies summary option, but don't overwrite summary if set */
2873 if (trace.summary_only)
2874 trace.summary = trace.summary_only;
2875
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002876 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2877 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002878 pr_err("Please specify something to trace.\n");
2879 return -1;
2880 }
2881
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002882 if (!trace.trace_syscalls && ev_qualifier_str) {
2883 pr_err("The -e option can't be used with --no-syscalls.\n");
2884 goto out;
2885 }
2886
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002887 if (output_name != NULL) {
2888 err = trace__open_output(&trace, output_name);
2889 if (err < 0) {
2890 perror("failed to create output file");
2891 goto out;
2892 }
2893 }
2894
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002895 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2896
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002897 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002898 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002899 struct strlist_config slist_config = {
2900 .dirname = system_path(STRACE_GROUPS_DIR),
2901 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002902
2903 trace.not_ev_qualifier = *s == '!';
2904 if (trace.not_ev_qualifier)
2905 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002906 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002907 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002908 fputs("Not enough memory to parse event qualifier",
2909 trace.output);
2910 err = -ENOMEM;
2911 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002912 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002913
2914 err = trace__validate_ev_qualifier(&trace);
2915 if (err)
2916 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002917 }
2918
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002919 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002920 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002921 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002922 fprintf(trace.output, "%s", bf);
2923 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002924 }
2925
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002926 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002927 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002928 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002929 fprintf(trace.output, "%s", bf);
2930 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002931 }
2932
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002933 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002934 trace.opts.target.system_wide = true;
2935
David Ahern6810fc92013-08-28 22:29:52 -06002936 if (input_name)
2937 err = trace__replay(&trace);
2938 else
2939 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002940
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002941out_close:
2942 if (output_name != NULL)
2943 fclose(trace.output);
2944out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002945 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002946}