blob: b8c6766301db90ddbe1dfa1fb65d2ab0a024ecc7 [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>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030046#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030047#include <linux/stringify.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030048
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030049#ifndef O_CLOEXEC
50# define O_CLOEXEC 02000000
51#endif
52
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030053struct trace {
54 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030055 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030056 struct {
57 int max;
58 struct syscall *table;
59 struct {
60 struct perf_evsel *sys_enter,
61 *sys_exit;
62 } events;
63 } syscalls;
64 struct record_opts opts;
65 struct perf_evlist *evlist;
66 struct machine *host;
67 struct thread *current;
68 u64 base_time;
69 FILE *output;
70 unsigned long nr_events;
71 struct strlist *ev_qualifier;
72 struct {
73 size_t nr;
74 int *entries;
75 } ev_qualifier_ids;
76 struct intlist *tid_list;
77 struct intlist *pid_list;
78 struct {
79 size_t nr;
80 pid_t *entries;
81 } filter_pids;
82 double duration_filter;
83 double runtime_ms;
84 struct {
85 u64 vfs_getname,
86 proc_getname;
87 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030088 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030089 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030090 bool not_ev_qualifier;
91 bool live;
92 bool full_time;
93 bool sched;
94 bool multiple_threads;
95 bool summary;
96 bool summary_only;
97 bool show_comm;
98 bool show_tool_stats;
99 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300100 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300101 bool force;
102 bool vfs_getname;
103 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300104 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300105};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300106
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300107struct tp_field {
108 int offset;
109 union {
110 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
111 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
112 };
113};
114
115#define TP_UINT_FIELD(bits) \
116static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
117{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500118 u##bits value; \
119 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
120 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300121}
122
123TP_UINT_FIELD(8);
124TP_UINT_FIELD(16);
125TP_UINT_FIELD(32);
126TP_UINT_FIELD(64);
127
128#define TP_UINT_FIELD__SWAPPED(bits) \
129static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
130{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500131 u##bits value; \
132 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300133 return bswap_##bits(value);\
134}
135
136TP_UINT_FIELD__SWAPPED(16);
137TP_UINT_FIELD__SWAPPED(32);
138TP_UINT_FIELD__SWAPPED(64);
139
140static int tp_field__init_uint(struct tp_field *field,
141 struct format_field *format_field,
142 bool needs_swap)
143{
144 field->offset = format_field->offset;
145
146 switch (format_field->size) {
147 case 1:
148 field->integer = tp_field__u8;
149 break;
150 case 2:
151 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
152 break;
153 case 4:
154 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
155 break;
156 case 8:
157 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
158 break;
159 default:
160 return -1;
161 }
162
163 return 0;
164}
165
166static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
167{
168 return sample->raw_data + field->offset;
169}
170
171static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
172{
173 field->offset = format_field->offset;
174 field->pointer = tp_field__ptr;
175 return 0;
176}
177
178struct syscall_tp {
179 struct tp_field id;
180 union {
181 struct tp_field args, ret;
182 };
183};
184
185static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
186 struct tp_field *field,
187 const char *name)
188{
189 struct format_field *format_field = perf_evsel__field(evsel, name);
190
191 if (format_field == NULL)
192 return -1;
193
194 return tp_field__init_uint(field, format_field, evsel->needs_swap);
195}
196
197#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
198 ({ struct syscall_tp *sc = evsel->priv;\
199 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
200
201static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
202 struct tp_field *field,
203 const char *name)
204{
205 struct format_field *format_field = perf_evsel__field(evsel, name);
206
207 if (format_field == NULL)
208 return -1;
209
210 return tp_field__init_ptr(field, format_field);
211}
212
213#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
214 ({ struct syscall_tp *sc = evsel->priv;\
215 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
216
217static void perf_evsel__delete_priv(struct perf_evsel *evsel)
218{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300219 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300220 perf_evsel__delete(evsel);
221}
222
Namhyung Kim96695d42013-11-12 08:51:45 -0300223static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
224{
225 evsel->priv = malloc(sizeof(struct syscall_tp));
226 if (evsel->priv != NULL) {
227 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
228 goto out_delete;
229
230 evsel->handler = handler;
231 return 0;
232 }
233
234 return -ENOMEM;
235
236out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300237 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300238 return -ENOENT;
239}
240
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300241static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300242{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300243 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300244
David Ahern9aca7f12013-12-04 19:41:39 -0700245 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200246 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700247 evsel = perf_evsel__newtp("syscalls", direction);
248
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200249 if (IS_ERR(evsel))
250 return NULL;
251
252 if (perf_evsel__init_syscall_tp(evsel, handler))
253 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300254
255 return evsel;
256
257out_delete:
258 perf_evsel__delete_priv(evsel);
259 return NULL;
260}
261
262#define perf_evsel__sc_tp_uint(evsel, name, sample) \
263 ({ struct syscall_tp *fields = evsel->priv; \
264 fields->name.integer(&fields->name, sample); })
265
266#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
267 ({ struct syscall_tp *fields = evsel->priv; \
268 fields->name.pointer(&fields->name, sample); })
269
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300270struct syscall_arg {
271 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300272 struct thread *thread;
273 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300274 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300275 u8 idx;
276 u8 mask;
277};
278
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300279struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300280 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300281 int nr_entries;
282 const char **entries;
283};
284
285#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
286 .nr_entries = ARRAY_SIZE(array), \
287 .entries = array, \
288}
289
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300290#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
291 .offset = off, \
292 .nr_entries = ARRAY_SIZE(array), \
293 .entries = array, \
294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300301 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302
303 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300304 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305
306 return scnprintf(bf, size, "%s", sa->entries[idx]);
307}
308
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300309static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
310 struct syscall_arg *arg)
311{
312 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
313}
314
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300315#define SCA_STRARRAY syscall_arg__scnprintf_strarray
316
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300317#if defined(__i386__) || defined(__x86_64__)
318/*
319 * FIXME: Make this available to all arches as soon as the ioctl beautifier
320 * gets rewritten to support all arches.
321 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300322static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
323 struct syscall_arg *arg)
324{
325 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
326}
327
328#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300329#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300330
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300331static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
332 struct syscall_arg *arg);
333
334#define SCA_FD syscall_arg__scnprintf_fd
335
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300336#ifndef AT_FDCWD
337#define AT_FDCWD -100
338#endif
339
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300340static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
341 struct syscall_arg *arg)
342{
343 int fd = arg->val;
344
345 if (fd == AT_FDCWD)
346 return scnprintf(bf, size, "CWD");
347
348 return syscall_arg__scnprintf_fd(bf, size, arg);
349}
350
351#define SCA_FDAT syscall_arg__scnprintf_fd_at
352
353static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
354 struct syscall_arg *arg);
355
356#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
357
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300358static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300359 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300360{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300361 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300362}
363
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300364#define SCA_HEX syscall_arg__scnprintf_hex
365
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300366static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
367 struct syscall_arg *arg)
368{
369 return scnprintf(bf, size, "%d", arg->val);
370}
371
372#define SCA_INT syscall_arg__scnprintf_int
373
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300374static const char *bpf_cmd[] = {
375 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
376 "MAP_GET_NEXT_KEY", "PROG_LOAD",
377};
378static DEFINE_STRARRAY(bpf_cmd);
379
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300380static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
381static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300382
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300383static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
384static DEFINE_STRARRAY(itimers);
385
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300386static const char *keyctl_options[] = {
387 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
388 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
389 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
390 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
391 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
392};
393static DEFINE_STRARRAY(keyctl_options);
394
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300395static const char *whences[] = { "SET", "CUR", "END",
396#ifdef SEEK_DATA
397"DATA",
398#endif
399#ifdef SEEK_HOLE
400"HOLE",
401#endif
402};
403static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300404
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300405static const char *fcntl_cmds[] = {
406 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
407 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
408 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
409 "F_GETOWNER_UIDS",
410};
411static DEFINE_STRARRAY(fcntl_cmds);
412
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300413static const char *rlimit_resources[] = {
414 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
415 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
416 "RTTIME",
417};
418static DEFINE_STRARRAY(rlimit_resources);
419
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300420static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
421static DEFINE_STRARRAY(sighow);
422
David Ahern4f8c1b72013-09-22 19:45:00 -0600423static const char *clockid[] = {
424 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300425 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
426 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600427};
428static DEFINE_STRARRAY(clockid);
429
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300430static const char *socket_families[] = {
431 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
432 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
433 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
434 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
435 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
436 "ALG", "NFC", "VSOCK",
437};
438static DEFINE_STRARRAY(socket_families);
439
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300440static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
441 struct syscall_arg *arg)
442{
443 size_t printed = 0;
444 int mode = arg->val;
445
446 if (mode == F_OK) /* 0 */
447 return scnprintf(bf, size, "F");
448#define P_MODE(n) \
449 if (mode & n##_OK) { \
450 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
451 mode &= ~n##_OK; \
452 }
453
454 P_MODE(R);
455 P_MODE(W);
456 P_MODE(X);
457#undef P_MODE
458
459 if (mode)
460 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
461
462 return printed;
463}
464
465#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
466
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300467static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
468 struct syscall_arg *arg);
469
470#define SCA_FILENAME syscall_arg__scnprintf_filename
471
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300472static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
473 struct syscall_arg *arg)
474{
475 int printed = 0, flags = arg->val;
476
477#define P_FLAG(n) \
478 if (flags & O_##n) { \
479 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
480 flags &= ~O_##n; \
481 }
482
483 P_FLAG(CLOEXEC);
484 P_FLAG(NONBLOCK);
485#undef P_FLAG
486
487 if (flags)
488 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
489
490 return printed;
491}
492
493#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
494
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300495#if defined(__i386__) || defined(__x86_64__)
496/*
497 * FIXME: Make this available to all arches.
498 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300499#define TCGETS 0x5401
500
501static const char *tioctls[] = {
502 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
503 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
504 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
505 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
506 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
507 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
508 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
509 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
510 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
511 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
512 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
513 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
514 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
515 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
516 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
517};
518
519static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300520#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300521
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300522#ifndef GRND_NONBLOCK
523#define GRND_NONBLOCK 0x0001
524#endif
525#ifndef GRND_RANDOM
526#define GRND_RANDOM 0x0002
527#endif
528
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300529static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
530 struct syscall_arg *arg)
531{
532 int printed = 0, flags = arg->val;
533
534#define P_FLAG(n) \
535 if (flags & GRND_##n) { \
536 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
537 flags &= ~GRND_##n; \
538 }
539
540 P_FLAG(RANDOM);
541 P_FLAG(NONBLOCK);
542#undef P_FLAG
543
544 if (flags)
545 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
546
547 return printed;
548}
549
550#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
551
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300552#define STRARRAY(arg, name, array) \
553 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
554 .arg_parm = { [arg] = &strarray__##array, }
555
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300556#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300557#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300558#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300559#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300560#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300561#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300562#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300563#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300564#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300565#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300566#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300567#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300568#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300569#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300570
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300571static struct syscall_fmt {
572 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300573 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300574 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300575 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300576 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300577 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300578 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300579 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300580} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300581 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300582 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300583 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300584 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300585 { .name = "brk", .hexret = true,
586 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300587 { .name = "chdir", .errmsg = true, },
588 { .name = "chmod", .errmsg = true, },
589 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600590 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300591 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300592 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300593 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300594 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300595 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300596 { .name = "dup", .errmsg = true, },
597 { .name = "dup2", .errmsg = true, },
598 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300599 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300600 { .name = "eventfd2", .errmsg = true,
601 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300602 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300603 { .name = "fadvise64", .errmsg = true, },
604 { .name = "fallocate", .errmsg = true, },
605 { .name = "fchdir", .errmsg = true, },
606 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300607 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300608 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300609 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300610 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300611 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300612 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300613 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300614 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300615 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300616 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300617 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
618 { .name = "fsetxattr", .errmsg = true, },
619 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300620 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300621 { .name = "fstatfs", .errmsg = true, },
622 { .name = "fsync", .errmsg = true, },
623 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300624 { .name = "futex", .errmsg = true,
625 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300626 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300627 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300628 { .name = "getdents", .errmsg = true, },
629 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300630 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300631 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300632 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300633 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300634 { .name = "getrandom", .errmsg = true,
635 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300636 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300637 { .name = "getxattr", .errmsg = true, },
638 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300639 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300640 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300641#if defined(__i386__) || defined(__x86_64__)
642/*
643 * FIXME: Make this available to all arches.
644 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300645 [1] = SCA_STRHEXARRAY, /* cmd */
646 [2] = SCA_HEX, /* arg */ },
647 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300648#else
649 [2] = SCA_HEX, /* arg */ }, },
650#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300651 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300652 { .name = "kill", .errmsg = true,
653 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300654 { .name = "lchown", .errmsg = true, },
655 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300656 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300657 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300658 { .name = "listxattr", .errmsg = true, },
659 { .name = "llistxattr", .errmsg = true, },
660 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300661 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300662 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300663 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300664 { .name = "lsetxattr", .errmsg = true, },
665 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
666 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300667 { .name = "madvise", .errmsg = true,
668 .arg_scnprintf = { [0] = SCA_HEX, /* start */
669 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300670 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300671 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300672 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
673 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300674 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300675 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300676 { .name = "mlock", .errmsg = true,
677 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
678 { .name = "mlockall", .errmsg = true,
679 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300680 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300681 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300682 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300683 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300684 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300685 .arg_scnprintf = { [0] = SCA_HEX, /* start */
686 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300687 { .name = "mq_unlink", .errmsg = true,
688 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300689 { .name = "mremap", .hexret = true,
690 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300691 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300692 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300693 { .name = "munlock", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300695 { .name = "munmap", .errmsg = true,
696 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300697 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300698 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300699 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300700 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300701 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300702 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300703 { .name = "open_by_handle_at", .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 Melo31cd3852013-09-02 16:40:40 -0300706 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300707 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
708 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300709 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300710 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300711 [3] = SCA_FD, /* group_fd */
712 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300713 { .name = "pipe2", .errmsg = true,
714 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300715 { .name = "poll", .errmsg = true, .timeout = true, },
716 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300717 { .name = "pread", .errmsg = true, .alias = "pread64", },
718 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300719 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300720 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
721 { .name = "pwritev", .errmsg = true, },
722 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300723 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300724 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300725 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300726 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300727 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300728 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300729 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300730 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300731 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300732 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300733 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300734 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300735 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300736 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300737 { .name = "rt_sigaction", .errmsg = true,
738 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300739 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300740 { .name = "rt_sigqueueinfo", .errmsg = true,
741 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
742 { .name = "rt_tgsigqueueinfo", .errmsg = true,
743 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300744 { .name = "sched_setscheduler", .errmsg = true,
745 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300746 { .name = "seccomp", .errmsg = true,
747 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
748 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300749 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300750 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300751 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300752 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300753 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300754 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300755 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300756 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300757 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300758 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300759 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300760 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300761 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300762 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300763 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
764 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300765 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300766 { .name = "socketpair", .errmsg = true,
767 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
768 [1] = SCA_SK_TYPE, /* type */ },
769 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300770 { .name = "stat", .errmsg = true, .alias = "newstat", },
771 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300772 { .name = "swapoff", .errmsg = true,
773 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
774 { .name = "swapon", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300776 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300777 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300778 { .name = "tgkill", .errmsg = true,
779 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
780 { .name = "tkill", .errmsg = true,
781 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300782 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300783 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300784 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300785 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
786 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300787 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300788 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
789 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300790 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300791 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300792 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300793 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300794 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300795 { .name = "write", .errmsg = true, },
796 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300797};
798
799static int syscall_fmt__cmp(const void *name, const void *fmtp)
800{
801 const struct syscall_fmt *fmt = fmtp;
802 return strcmp(name, fmt->name);
803}
804
805static struct syscall_fmt *syscall_fmt__find(const char *name)
806{
807 const int nmemb = ARRAY_SIZE(syscall_fmts);
808 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
809}
810
811struct syscall {
812 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300813 int nr_args;
814 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300815 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300816 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300818 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300819 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300820};
821
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200822static size_t fprintf_duration(unsigned long t, FILE *fp)
823{
824 double duration = (double)t / NSEC_PER_MSEC;
825 size_t printed = fprintf(fp, "(");
826
827 if (duration >= 1.0)
828 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
829 else if (duration >= 0.01)
830 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
831 else
832 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300833 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200834}
835
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300836/**
837 * filename.ptr: The filename char pointer that will be vfs_getname'd
838 * filename.entry_str_pos: Where to insert the string translated from
839 * filename.ptr by the vfs_getname tracepoint/kprobe.
840 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300841struct thread_trace {
842 u64 entry_time;
843 u64 exit_time;
844 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300845 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400846 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300847 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300848 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300849 struct {
850 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300851 short int entry_str_pos;
852 bool pending_open;
853 unsigned int namelen;
854 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300855 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300856 struct {
857 int max;
858 char **table;
859 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600860
861 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300862};
863
864static struct thread_trace *thread_trace__new(void)
865{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300866 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
867
868 if (ttrace)
869 ttrace->paths.max = -1;
870
David Ahernbf2575c2013-10-08 21:26:53 -0600871 ttrace->syscall_stats = intlist__new(NULL);
872
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300873 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300874}
875
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300876static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300877{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300878 struct thread_trace *ttrace;
879
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300880 if (thread == NULL)
881 goto fail;
882
Namhyung Kim89dceb22014-10-06 09:46:03 +0900883 if (thread__priv(thread) == NULL)
884 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300885
Namhyung Kim89dceb22014-10-06 09:46:03 +0900886 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300887 goto fail;
888
Namhyung Kim89dceb22014-10-06 09:46:03 +0900889 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300890 ++ttrace->nr_events;
891
892 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300893fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300894 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895 "WARNING: not enough memory, dropping samples!\n");
896 return NULL;
897}
898
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400899#define TRACE_PFMAJ (1 << 0)
900#define TRACE_PFMIN (1 << 1)
901
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300902static const size_t trace__entry_str_size = 2048;
903
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300904static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300905{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900906 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300907
908 if (fd > ttrace->paths.max) {
909 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
910
911 if (npath == NULL)
912 return -1;
913
914 if (ttrace->paths.max != -1) {
915 memset(npath + ttrace->paths.max + 1, 0,
916 (fd - ttrace->paths.max) * sizeof(char *));
917 } else {
918 memset(npath, 0, (fd + 1) * sizeof(char *));
919 }
920
921 ttrace->paths.table = npath;
922 ttrace->paths.max = fd;
923 }
924
925 ttrace->paths.table[fd] = strdup(pathname);
926
927 return ttrace->paths.table[fd] != NULL ? 0 : -1;
928}
929
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300930static int thread__read_fd_path(struct thread *thread, int fd)
931{
932 char linkname[PATH_MAX], pathname[PATH_MAX];
933 struct stat st;
934 int ret;
935
936 if (thread->pid_ == thread->tid) {
937 scnprintf(linkname, sizeof(linkname),
938 "/proc/%d/fd/%d", thread->pid_, fd);
939 } else {
940 scnprintf(linkname, sizeof(linkname),
941 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
942 }
943
944 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
945 return -1;
946
947 ret = readlink(linkname, pathname, sizeof(pathname));
948
949 if (ret < 0 || ret > st.st_size)
950 return -1;
951
952 pathname[ret] = '\0';
953 return trace__set_fd_pathname(thread, fd, pathname);
954}
955
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300956static const char *thread__fd_path(struct thread *thread, int fd,
957 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300958{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900959 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300960
961 if (ttrace == NULL)
962 return NULL;
963
964 if (fd < 0)
965 return NULL;
966
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300967 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300968 if (!trace->live)
969 return NULL;
970 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300971 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300972 return NULL;
973 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300974
975 return ttrace->paths.table[fd];
976}
977
978static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
979 struct syscall_arg *arg)
980{
981 int fd = arg->val;
982 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300983 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984
985 if (path)
986 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
987
988 return printed;
989}
990
991static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
992 struct syscall_arg *arg)
993{
994 int fd = arg->val;
995 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +0900996 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300998 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
999 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001000
1001 return printed;
1002}
1003
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001004static void thread__set_filename_pos(struct thread *thread, const char *bf,
1005 unsigned long ptr)
1006{
1007 struct thread_trace *ttrace = thread__priv(thread);
1008
1009 ttrace->filename.ptr = ptr;
1010 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1011}
1012
1013static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1014 struct syscall_arg *arg)
1015{
1016 unsigned long ptr = arg->val;
1017
1018 if (!arg->trace->vfs_getname)
1019 return scnprintf(bf, size, "%#x", ptr);
1020
1021 thread__set_filename_pos(arg->thread, bf, ptr);
1022 return 0;
1023}
1024
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001025static bool trace__filter_duration(struct trace *trace, double t)
1026{
1027 return t < (trace->duration_filter * NSEC_PER_MSEC);
1028}
1029
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001030static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1031{
1032 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1033
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001034 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001035}
1036
Namhyung Kimf15eb532012-10-05 14:02:16 +09001037static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001038static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001039
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001040static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001041{
1042 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001043 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001044}
1045
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001046static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001047 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001048{
1049 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001050 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001051
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001052 if (trace->multiple_threads) {
1053 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001054 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001055 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001056 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001057
1058 return printed;
1059}
1060
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001061static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001062 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001063{
1064 int ret = 0;
1065
1066 switch (event->header.type) {
1067 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001068 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001069 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001070 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001071 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001072 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001073 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001074 break;
1075 }
1076
1077 return ret;
1078}
1079
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001080static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001081 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001082 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001083 struct machine *machine)
1084{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001085 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001086 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001087}
1088
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001089static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1090{
1091 struct machine *machine = vmachine;
1092
1093 if (machine->kptr_restrict_warned)
1094 return NULL;
1095
1096 if (symbol_conf.kptr_restrict) {
1097 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1098 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1099 "Kernel samples will not be resolved.\n");
1100 machine->kptr_restrict_warned = true;
1101 return NULL;
1102 }
1103
1104 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1105}
1106
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1108{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001109 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110
1111 if (err)
1112 return err;
1113
David Ahern8fb598e2013-09-28 13:13:00 -06001114 trace->host = machine__new_host();
1115 if (trace->host == NULL)
1116 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001117
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001118 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001119 return -errno;
1120
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001121 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001122 evlist->threads, trace__tool_process, false,
1123 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001124 if (err)
1125 symbol__exit();
1126
1127 return err;
1128}
1129
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001130static int syscall__set_arg_fmts(struct syscall *sc)
1131{
1132 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001133 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001134
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001135 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001136 if (sc->arg_scnprintf == NULL)
1137 return -1;
1138
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001139 if (sc->fmt)
1140 sc->arg_parm = sc->fmt->arg_parm;
1141
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001142 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001143 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1144 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001145 else if (strcmp(field->type, "const char *") == 0 &&
1146 (strcmp(field->name, "filename") == 0 ||
1147 strcmp(field->name, "path") == 0 ||
1148 strcmp(field->name, "pathname") == 0))
1149 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001150 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001151 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001152 else if (strcmp(field->type, "pid_t") == 0)
1153 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001154 else if (strcmp(field->type, "umode_t") == 0)
1155 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001156 else if ((strcmp(field->type, "int") == 0 ||
1157 strcmp(field->type, "unsigned int") == 0 ||
1158 strcmp(field->type, "long") == 0) &&
1159 (len = strlen(field->name)) >= 2 &&
1160 strcmp(field->name + len - 2, "fd") == 0) {
1161 /*
1162 * /sys/kernel/tracing/events/syscalls/sys_enter*
1163 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1164 * 65 int
1165 * 23 unsigned int
1166 * 7 unsigned long
1167 */
1168 sc->arg_scnprintf[idx] = SCA_FD;
1169 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001170 ++idx;
1171 }
1172
1173 return 0;
1174}
1175
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001176static int trace__read_syscall_info(struct trace *trace, int id)
1177{
1178 char tp_name[128];
1179 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001180 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001181
1182 if (name == NULL)
1183 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001184
1185 if (id > trace->syscalls.max) {
1186 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1187
1188 if (nsyscalls == NULL)
1189 return -1;
1190
1191 if (trace->syscalls.max != -1) {
1192 memset(nsyscalls + trace->syscalls.max + 1, 0,
1193 (id - trace->syscalls.max) * sizeof(*sc));
1194 } else {
1195 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1196 }
1197
1198 trace->syscalls.table = nsyscalls;
1199 trace->syscalls.max = id;
1200 }
1201
1202 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001203 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001204
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001205 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001206
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001207 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001208 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001209
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001210 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001211 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001212 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001213 }
1214
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001215 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001216 return -1;
1217
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001218 sc->args = sc->tp_format->format.fields;
1219 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001220 /*
1221 * We need to check and discard the first variable '__syscall_nr'
1222 * or 'nr' that mean the syscall number. It is needless here.
1223 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1224 */
1225 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001226 sc->args = sc->args->next;
1227 --sc->nr_args;
1228 }
1229
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001230 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1231
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001232 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001233}
1234
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001235static int trace__validate_ev_qualifier(struct trace *trace)
1236{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001237 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001238 struct str_node *pos;
1239
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001240 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1241 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1242 sizeof(trace->ev_qualifier_ids.entries[0]));
1243
1244 if (trace->ev_qualifier_ids.entries == NULL) {
1245 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1246 trace->output);
1247 err = -EINVAL;
1248 goto out;
1249 }
1250
1251 i = 0;
1252
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001253 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001254 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001255 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001256
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001257 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001258 if (err == 0) {
1259 fputs("Error:\tInvalid syscall ", trace->output);
1260 err = -EINVAL;
1261 } else {
1262 fputs(", ", trace->output);
1263 }
1264
1265 fputs(sc, trace->output);
1266 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001267
1268 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001269 }
1270
1271 if (err < 0) {
1272 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1273 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001274 zfree(&trace->ev_qualifier_ids.entries);
1275 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001276 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001277out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001278 return err;
1279}
1280
David Ahern55d43bc2015-02-19 15:00:22 -05001281/*
1282 * args is to be interpreted as a series of longs but we need to handle
1283 * 8-byte unaligned accesses. args points to raw_data within the event
1284 * and raw_data is guaranteed to be 8-byte unaligned because it is
1285 * preceded by raw_size which is a u32. So we need to copy args to a temp
1286 * variable to read it. Most notably this avoids extended load instructions
1287 * on unaligned addresses
1288 */
1289
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001290static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001291 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001292 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001293{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001294 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001295 unsigned char *p;
1296 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001297
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001298 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001299 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001300 u8 bit = 1;
1301 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001302 .idx = 0,
1303 .mask = 0,
1304 .trace = trace,
1305 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001306 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001307
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001308 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001309 field = field->next, ++arg.idx, bit <<= 1) {
1310 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001311 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001312
1313 /* special care for unaligned accesses */
1314 p = args + sizeof(unsigned long) * arg.idx;
1315 memcpy(&val, p, sizeof(val));
1316
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001317 /*
1318 * Suppress this argument if its value is zero and
1319 * and we don't have a string associated in an
1320 * strarray for it.
1321 */
David Ahern55d43bc2015-02-19 15:00:22 -05001322 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001323 !(sc->arg_scnprintf &&
1324 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1325 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001326 continue;
1327
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001328 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001329 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001330 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001331 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001332 if (sc->arg_parm)
1333 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001334 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1335 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001336 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001337 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001338 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001339 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001340 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001341 } else if (IS_ERR(sc->tp_format)) {
1342 /*
1343 * If we managed to read the tracepoint /format file, then we
1344 * may end up not having any args, like with gettid(), so only
1345 * print the raw args when we didn't manage to read it.
1346 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001347 int i = 0;
1348
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001349 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001350 /* special care for unaligned accesses */
1351 p = args + sizeof(unsigned long) * i;
1352 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001353 printed += scnprintf(bf + printed, size - printed,
1354 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001355 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001356 ++i;
1357 }
1358 }
1359
1360 return printed;
1361}
1362
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001363typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001364 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001365 struct perf_sample *sample);
1366
1367static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001368 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001369{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001370
1371 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001372
1373 /*
1374 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1375 * before that, leaving at a higher verbosity level till that is
1376 * explained. Reproduced with plain ftrace with:
1377 *
1378 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1379 * grep "NR -1 " /t/trace_pipe
1380 *
1381 * After generating some load on the machine.
1382 */
1383 if (verbose > 1) {
1384 static u64 n;
1385 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1386 id, perf_evsel__name(evsel), ++n);
1387 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001388 return NULL;
1389 }
1390
1391 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1392 trace__read_syscall_info(trace, id))
1393 goto out_cant_read;
1394
1395 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1396 goto out_cant_read;
1397
1398 return &trace->syscalls.table[id];
1399
1400out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001401 if (verbose) {
1402 fprintf(trace->output, "Problems reading syscall %d", id);
1403 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1404 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1405 fputs(" information\n", trace->output);
1406 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001407 return NULL;
1408}
1409
David Ahernbf2575c2013-10-08 21:26:53 -06001410static void thread__update_stats(struct thread_trace *ttrace,
1411 int id, struct perf_sample *sample)
1412{
1413 struct int_node *inode;
1414 struct stats *stats;
1415 u64 duration = 0;
1416
1417 inode = intlist__findnew(ttrace->syscall_stats, id);
1418 if (inode == NULL)
1419 return;
1420
1421 stats = inode->priv;
1422 if (stats == NULL) {
1423 stats = malloc(sizeof(struct stats));
1424 if (stats == NULL)
1425 return;
1426 init_stats(stats);
1427 inode->priv = stats;
1428 }
1429
1430 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1431 duration = sample->time - ttrace->entry_time;
1432
1433 update_stats(stats, duration);
1434}
1435
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001436static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1437{
1438 struct thread_trace *ttrace;
1439 u64 duration;
1440 size_t printed;
1441
1442 if (trace->current == NULL)
1443 return 0;
1444
1445 ttrace = thread__priv(trace->current);
1446
1447 if (!ttrace->entry_pending)
1448 return 0;
1449
1450 duration = sample->time - ttrace->entry_time;
1451
1452 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1453 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1454 ttrace->entry_pending = false;
1455
1456 return printed;
1457}
1458
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001459static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001460 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001461 struct perf_sample *sample)
1462{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001463 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001464 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001465 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001466 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001467 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001468 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001469 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001470
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001471 if (sc == NULL)
1472 return -1;
1473
David Ahern8fb598e2013-09-28 13:13:00 -06001474 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001475 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001476 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001477 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001478
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001479 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001480
1481 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001482 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001483 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001484 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001485 }
1486
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001487 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001488 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001489
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001490 ttrace->entry_time = sample->time;
1491 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001492 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001493
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001494 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001495 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001496
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001497 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001498 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001499 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001500 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001501 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001502 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001503 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001504 /* See trace__vfs_getname & trace__sys_exit */
1505 ttrace->filename.pending_open = false;
1506 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001507
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001508 if (trace->current != thread) {
1509 thread__put(trace->current);
1510 trace->current = thread__get(thread);
1511 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001512 err = 0;
1513out_put:
1514 thread__put(thread);
1515 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001516}
1517
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001518static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1519 struct perf_sample *sample,
1520 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001521{
1522 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001523
1524 if (machine__resolve(trace->host, &al, sample) < 0 ||
1525 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1526 return -1;
1527
1528 return 0;
1529}
1530
1531static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1532{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001533 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001534 const unsigned int print_opts = EVSEL__PRINT_SYM |
1535 EVSEL__PRINT_DSO |
1536 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001537
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001538 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001539}
1540
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001541static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001542 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001543 struct perf_sample *sample)
1544{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001545 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001546 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001547 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001548 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001549 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001550 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001551
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001552 if (sc == NULL)
1553 return -1;
1554
David Ahern8fb598e2013-09-28 13:13:00 -06001555 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001556 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001557 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001558 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001559
David Ahernbf2575c2013-10-08 21:26:53 -06001560 if (trace->summary)
1561 thread__update_stats(ttrace, id, sample);
1562
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001563 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001564
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001565 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001566 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1567 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001568 ++trace->stats.vfs_getname;
1569 }
1570
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001571 ttrace->exit_time = sample->time;
1572
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001573 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001574 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001575 if (trace__filter_duration(trace, duration))
1576 goto out;
1577 } else if (trace->duration_filter)
1578 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001579
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001580 if (sample->callchain) {
1581 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1582 if (callchain_ret == 0) {
1583 if (callchain_cursor.nr < trace->min_stack)
1584 goto out;
1585 callchain_ret = 1;
1586 }
1587 }
1588
David Ahernfd2eaba2013-11-12 09:31:15 -07001589 if (trace->summary_only)
1590 goto out;
1591
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001592 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001593
1594 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001595 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001596 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001597 fprintf(trace->output, " ... [");
1598 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1599 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001600 }
1601
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001602 if (sc->fmt == NULL) {
1603signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001604 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001605 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001606 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001607 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001608 *e = audit_errno_to_name(-ret);
1609
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001610 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001611 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001612 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001613 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001614 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001615 else if (sc->fmt->errpid) {
1616 struct thread *child = machine__find_thread(trace->host, ret, ret);
1617
1618 if (child != NULL) {
1619 fprintf(trace->output, ") = %ld", ret);
1620 if (child->comm_set)
1621 fprintf(trace->output, " (%s)", thread__comm_str(child));
1622 thread__put(child);
1623 }
1624 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001625 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001626
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001627 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001628
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001629 if (callchain_ret > 0)
1630 trace__fprintf_callchain(trace, sample);
1631 else if (callchain_ret < 0)
1632 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001633out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001634 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001635 err = 0;
1636out_put:
1637 thread__put(thread);
1638 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001639}
1640
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001641static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001642 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001643 struct perf_sample *sample)
1644{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001645 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1646 struct thread_trace *ttrace;
1647 size_t filename_len, entry_str_len, to_move;
1648 ssize_t remaining_space;
1649 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001650 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001651
1652 if (!thread)
1653 goto out;
1654
1655 ttrace = thread__priv(thread);
1656 if (!ttrace)
1657 goto out;
1658
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001659 filename_len = strlen(filename);
1660
1661 if (ttrace->filename.namelen < filename_len) {
1662 char *f = realloc(ttrace->filename.name, filename_len + 1);
1663
1664 if (f == NULL)
1665 goto out;
1666
1667 ttrace->filename.namelen = filename_len;
1668 ttrace->filename.name = f;
1669 }
1670
1671 strcpy(ttrace->filename.name, filename);
1672 ttrace->filename.pending_open = true;
1673
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001674 if (!ttrace->filename.ptr)
1675 goto out;
1676
1677 entry_str_len = strlen(ttrace->entry_str);
1678 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1679 if (remaining_space <= 0)
1680 goto out;
1681
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001682 if (filename_len > (size_t)remaining_space) {
1683 filename += filename_len - remaining_space;
1684 filename_len = remaining_space;
1685 }
1686
1687 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1688 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1689 memmove(pos + filename_len, pos, to_move);
1690 memcpy(pos, filename, filename_len);
1691
1692 ttrace->filename.ptr = 0;
1693 ttrace->filename.entry_str_pos = 0;
1694out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001695 return 0;
1696}
1697
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001698static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001699 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001700 struct perf_sample *sample)
1701{
1702 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1703 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001704 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001705 sample->pid,
1706 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001707 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001708
1709 if (ttrace == NULL)
1710 goto out_dump;
1711
1712 ttrace->runtime_ms += runtime_ms;
1713 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001714 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001715 return 0;
1716
1717out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001718 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001719 evsel->name,
1720 perf_evsel__strval(evsel, sample, "comm"),
1721 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1722 runtime,
1723 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001724 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001725 return 0;
1726}
1727
Wang Nan1d6c9402016-02-26 09:31:55 +00001728static void bpf_output__printer(enum binary_printer_ops op,
1729 unsigned int val, void *extra)
1730{
1731 FILE *output = extra;
1732 unsigned char ch = (unsigned char)val;
1733
1734 switch (op) {
1735 case BINARY_PRINT_CHAR_DATA:
1736 fprintf(output, "%c", isprint(ch) ? ch : '.');
1737 break;
1738 case BINARY_PRINT_DATA_BEGIN:
1739 case BINARY_PRINT_LINE_BEGIN:
1740 case BINARY_PRINT_ADDR:
1741 case BINARY_PRINT_NUM_DATA:
1742 case BINARY_PRINT_NUM_PAD:
1743 case BINARY_PRINT_SEP:
1744 case BINARY_PRINT_CHAR_PAD:
1745 case BINARY_PRINT_LINE_END:
1746 case BINARY_PRINT_DATA_END:
1747 default:
1748 break;
1749 }
1750}
1751
1752static void bpf_output__fprintf(struct trace *trace,
1753 struct perf_sample *sample)
1754{
1755 print_binary(sample->raw_data, sample->raw_size, 8,
1756 bpf_output__printer, trace->output);
1757}
1758
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001759static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1760 union perf_event *event __maybe_unused,
1761 struct perf_sample *sample)
1762{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001763 int callchain_ret = 0;
1764
1765 if (sample->callchain) {
1766 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1767 if (callchain_ret == 0) {
1768 if (callchain_cursor.nr < trace->min_stack)
1769 goto out;
1770 callchain_ret = 1;
1771 }
1772 }
1773
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001774 trace__printf_interrupted_entry(trace, sample);
1775 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001776
1777 if (trace->trace_syscalls)
1778 fprintf(trace->output, "( ): ");
1779
1780 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001781
Wang Nan1d6c9402016-02-26 09:31:55 +00001782 if (perf_evsel__is_bpf_output(evsel)) {
1783 bpf_output__fprintf(trace, sample);
1784 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001785 event_format__fprintf(evsel->tp_format, sample->cpu,
1786 sample->raw_data, sample->raw_size,
1787 trace->output);
1788 }
1789
1790 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001791
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001792 if (callchain_ret > 0)
1793 trace__fprintf_callchain(trace, sample);
1794 else if (callchain_ret < 0)
1795 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1796out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001797 return 0;
1798}
1799
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001800static void print_location(FILE *f, struct perf_sample *sample,
1801 struct addr_location *al,
1802 bool print_dso, bool print_sym)
1803{
1804
1805 if ((verbose || print_dso) && al->map)
1806 fprintf(f, "%s@", al->map->dso->long_name);
1807
1808 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001809 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001810 al->addr - al->sym->start);
1811 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001812 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001813 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001814 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001815}
1816
1817static int trace__pgfault(struct trace *trace,
1818 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001819 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001820 struct perf_sample *sample)
1821{
1822 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001823 struct addr_location al;
1824 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001825 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001826 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001827 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001828
1829 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001830
1831 if (sample->callchain) {
1832 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1833 if (callchain_ret == 0) {
1834 if (callchain_cursor.nr < trace->min_stack)
1835 goto out_put;
1836 callchain_ret = 1;
1837 }
1838 }
1839
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001840 ttrace = thread__trace(thread, trace->output);
1841 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001842 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001843
1844 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1845 ttrace->pfmaj++;
1846 else
1847 ttrace->pfmin++;
1848
1849 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001850 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001851
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001852 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001853 sample->ip, &al);
1854
1855 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1856
1857 fprintf(trace->output, "%sfault [",
1858 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1859 "maj" : "min");
1860
1861 print_location(trace->output, sample, &al, false, true);
1862
1863 fprintf(trace->output, "] => ");
1864
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001865 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001866 sample->addr, &al);
1867
1868 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001869 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001870 MAP__FUNCTION, sample->addr, &al);
1871
1872 if (al.map)
1873 map_type = 'x';
1874 else
1875 map_type = '?';
1876 }
1877
1878 print_location(trace->output, sample, &al, true, false);
1879
1880 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001881
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001882 if (callchain_ret > 0)
1883 trace__fprintf_callchain(trace, sample);
1884 else if (callchain_ret < 0)
1885 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001886out:
1887 err = 0;
1888out_put:
1889 thread__put(thread);
1890 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001891}
1892
David Ahernbdc89662013-08-28 22:29:53 -06001893static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1894{
1895 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1896 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1897 return false;
1898
1899 if (trace->pid_list || trace->tid_list)
1900 return true;
1901
1902 return false;
1903}
1904
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001905static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001906 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001907 struct perf_sample *sample)
1908{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001909 /*
1910 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1911 * and don't use sample->time unconditionally, we may end up having
1912 * some other event in the future without PERF_SAMPLE_TIME for good
1913 * reason, i.e. we may not be interested in its timestamps, just in
1914 * it taking place, picking some piece of information when it
1915 * appears in our event stream (vfs_getname comes to mind).
1916 */
1917 if (trace->base_time == 0 && !trace->full_time &&
1918 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001919 trace->base_time = sample->time;
1920}
1921
David Ahern6810fc92013-08-28 22:29:52 -06001922static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001923 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001924 struct perf_sample *sample,
1925 struct perf_evsel *evsel,
1926 struct machine *machine __maybe_unused)
1927{
1928 struct trace *trace = container_of(tool, struct trace, tool);
1929 int err = 0;
1930
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001931 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001932
David Ahernbdc89662013-08-28 22:29:53 -06001933 if (skip_sample(trace, sample))
1934 return 0;
1935
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001936 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001937
David Ahern31605652013-12-04 19:41:41 -07001938 if (handler) {
1939 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001940 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001941 }
David Ahern6810fc92013-08-28 22:29:52 -06001942
1943 return err;
1944}
1945
David Ahernbdc89662013-08-28 22:29:53 -06001946static int parse_target_str(struct trace *trace)
1947{
1948 if (trace->opts.target.pid) {
1949 trace->pid_list = intlist__new(trace->opts.target.pid);
1950 if (trace->pid_list == NULL) {
1951 pr_err("Error parsing process id string\n");
1952 return -EINVAL;
1953 }
1954 }
1955
1956 if (trace->opts.target.tid) {
1957 trace->tid_list = intlist__new(trace->opts.target.tid);
1958 if (trace->tid_list == NULL) {
1959 pr_err("Error parsing thread id string\n");
1960 return -EINVAL;
1961 }
1962 }
1963
1964 return 0;
1965}
1966
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001967static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001968{
1969 unsigned int rec_argc, i, j;
1970 const char **rec_argv;
1971 const char * const record_args[] = {
1972 "record",
1973 "-R",
1974 "-m", "1024",
1975 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001976 };
1977
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001978 const char * const sc_args[] = { "-e", };
1979 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1980 const char * const majpf_args[] = { "-e", "major-faults" };
1981 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1982 const char * const minpf_args[] = { "-e", "minor-faults" };
1983 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1984
David Ahern9aca7f12013-12-04 19:41:39 -07001985 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001986 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1987 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001988 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1989
1990 if (rec_argv == NULL)
1991 return -ENOMEM;
1992
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001993 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001994 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001995 rec_argv[j++] = record_args[i];
1996
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001997 if (trace->trace_syscalls) {
1998 for (i = 0; i < sc_args_nr; i++)
1999 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002000
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002001 /* event string may be different for older kernels - e.g., RHEL6 */
2002 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2003 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2004 else if (is_valid_tracepoint("syscalls:sys_enter"))
2005 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2006 else {
2007 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2008 return -1;
2009 }
David Ahern9aca7f12013-12-04 19:41:39 -07002010 }
David Ahern9aca7f12013-12-04 19:41:39 -07002011
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002012 if (trace->trace_pgfaults & TRACE_PFMAJ)
2013 for (i = 0; i < majpf_args_nr; i++)
2014 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002015
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002016 if (trace->trace_pgfaults & TRACE_PFMIN)
2017 for (i = 0; i < minpf_args_nr; i++)
2018 rec_argv[j++] = minpf_args[i];
2019
2020 for (i = 0; i < (unsigned int)argc; i++)
2021 rec_argv[j++] = argv[i];
2022
2023 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002024}
2025
David Ahernbf2575c2013-10-08 21:26:53 -06002026static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2027
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002028static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002029{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002030 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002031
2032 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002033 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002034
2035 if (perf_evsel__field(evsel, "pathname") == NULL) {
2036 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002037 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002038 }
2039
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002040 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002041 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002042 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002043}
2044
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002045static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002046{
2047 struct perf_evsel *evsel;
2048 struct perf_event_attr attr = {
2049 .type = PERF_TYPE_SOFTWARE,
2050 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002051 };
2052
2053 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002054 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002055
2056 event_attr_init(&attr);
2057
2058 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002059 if (evsel)
2060 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002061
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002062 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002063}
2064
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002065static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2066{
2067 const u32 type = event->header.type;
2068 struct perf_evsel *evsel;
2069
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002070 if (type != PERF_RECORD_SAMPLE) {
2071 trace__process_event(trace, trace->host, event, sample);
2072 return;
2073 }
2074
2075 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2076 if (evsel == NULL) {
2077 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2078 return;
2079 }
2080
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002081 trace__set_base_time(trace, evsel, sample);
2082
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002083 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2084 sample->raw_data == NULL) {
2085 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2086 perf_evsel__name(evsel), sample->tid,
2087 sample->cpu, sample->raw_size);
2088 } else {
2089 tracepoint_handler handler = evsel->handler;
2090 handler(trace, evsel, event, sample);
2091 }
2092}
2093
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002094static int trace__add_syscall_newtp(struct trace *trace)
2095{
2096 int ret = -1;
2097 struct perf_evlist *evlist = trace->evlist;
2098 struct perf_evsel *sys_enter, *sys_exit;
2099
2100 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2101 if (sys_enter == NULL)
2102 goto out;
2103
2104 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2105 goto out_delete_sys_enter;
2106
2107 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2108 if (sys_exit == NULL)
2109 goto out_delete_sys_enter;
2110
2111 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2112 goto out_delete_sys_exit;
2113
2114 perf_evlist__add(evlist, sys_enter);
2115 perf_evlist__add(evlist, sys_exit);
2116
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002117 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002118 /*
2119 * We're interested only in the user space callchain
2120 * leading to the syscall, allow overriding that for
2121 * debugging reasons using --kernel_syscall_callchains
2122 */
2123 sys_exit->attr.exclude_callchain_kernel = 1;
2124 }
2125
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002126 trace->syscalls.events.sys_enter = sys_enter;
2127 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002128
2129 ret = 0;
2130out:
2131 return ret;
2132
2133out_delete_sys_exit:
2134 perf_evsel__delete_priv(sys_exit);
2135out_delete_sys_enter:
2136 perf_evsel__delete_priv(sys_enter);
2137 goto out;
2138}
2139
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002140static int trace__set_ev_qualifier_filter(struct trace *trace)
2141{
2142 int err = -1;
2143 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2144 trace->ev_qualifier_ids.nr,
2145 trace->ev_qualifier_ids.entries);
2146
2147 if (filter == NULL)
2148 goto out_enomem;
2149
2150 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2151 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2152
2153 free(filter);
2154out:
2155 return err;
2156out_enomem:
2157 errno = ENOMEM;
2158 goto out;
2159}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002160
Namhyung Kimf15eb532012-10-05 14:02:16 +09002161static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002162{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002163 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002164 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002165 int err = -1, i;
2166 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002167 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002168 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002169
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002170 trace->live = true;
2171
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002172 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002173 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002174
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002175 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002176 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002177
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002178 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2179 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2180 if (pgfault_maj == NULL)
2181 goto out_error_mem;
2182 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002183 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002184
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002185 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2186 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2187 if (pgfault_min == NULL)
2188 goto out_error_mem;
2189 perf_evlist__add(evlist, pgfault_min);
2190 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002191
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002192 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002193 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2194 trace__sched_stat_runtime))
2195 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002196
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002197 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2198 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002199 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002200 goto out_delete_evlist;
2201 }
2202
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002203 err = trace__symbols_init(trace, evlist);
2204 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002205 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002206 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002207 }
2208
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002209 perf_evlist__config(evlist, &trace->opts, NULL);
2210
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002211 if (callchain_param.enabled) {
2212 bool use_identifier = false;
2213
2214 if (trace->syscalls.events.sys_exit) {
2215 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2216 &trace->opts, &callchain_param);
2217 use_identifier = true;
2218 }
2219
2220 if (pgfault_maj) {
2221 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2222 use_identifier = true;
2223 }
2224
2225 if (pgfault_min) {
2226 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2227 use_identifier = true;
2228 }
2229
2230 if (use_identifier) {
2231 /*
2232 * Now we have evsels with different sample_ids, use
2233 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2234 * from a fixed position in each ring buffer record.
2235 *
2236 * As of this the changeset introducing this comment, this
2237 * isn't strictly needed, as the fields that can come before
2238 * PERF_SAMPLE_ID are all used, but we'll probably disable
2239 * some of those for things like copying the payload of
2240 * pointer syscall arguments, and for vfs_getname we don't
2241 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2242 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2243 */
2244 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2245 perf_evlist__reset_sample_bit(evlist, ID);
2246 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002247 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002248
Namhyung Kimf15eb532012-10-05 14:02:16 +09002249 signal(SIGCHLD, sig_handler);
2250 signal(SIGINT, sig_handler);
2251
2252 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002253 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002254 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002255 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002256 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002257 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002258 }
2259 }
2260
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002262 if (err < 0)
2263 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002264
Wang Nanba504232016-02-26 09:31:54 +00002265 err = bpf__apply_obj_config();
2266 if (err) {
2267 char errbuf[BUFSIZ];
2268
2269 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2270 pr_err("ERROR: Apply config to BPF failed: %s\n",
2271 errbuf);
2272 goto out_error_open;
2273 }
2274
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002275 /*
2276 * Better not use !target__has_task() here because we need to cover the
2277 * case where no threads were specified in the command line, but a
2278 * workload was, and in that case we will fill in the thread_map when
2279 * we fork the workload in perf_evlist__prepare_workload.
2280 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002281 if (trace->filter_pids.nr > 0)
2282 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002283 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002284 err = perf_evlist__set_filter_pid(evlist, getpid());
2285
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002286 if (err < 0)
2287 goto out_error_mem;
2288
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002289 if (trace->ev_qualifier_ids.nr > 0) {
2290 err = trace__set_ev_qualifier_filter(trace);
2291 if (err < 0)
2292 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002293
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002294 pr_debug("event qualifier tracepoint filter: %s\n",
2295 trace->syscalls.events.sys_exit->filter);
2296 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002297
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002298 err = perf_evlist__apply_filters(evlist, &evsel);
2299 if (err < 0)
2300 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002301
Jiri Olsaf8850372013-11-28 17:57:22 +01002302 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002303 if (err < 0)
2304 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002305
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002306 if (!target__none(&trace->opts.target))
2307 perf_evlist__enable(evlist);
2308
Namhyung Kimf15eb532012-10-05 14:02:16 +09002309 if (forks)
2310 perf_evlist__start_workload(evlist);
2311
Jiri Olsae13798c2015-06-23 00:36:02 +02002312 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002313 evlist->threads->nr > 1 ||
2314 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002315again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002316 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002317
2318 for (i = 0; i < evlist->nr_mmaps; i++) {
2319 union perf_event *event;
2320
2321 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002323
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002324 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002325
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002326 err = perf_evlist__parse_sample(evlist, event, &sample);
2327 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002328 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002329 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002330 }
2331
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002332 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002333next_event:
2334 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002335
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002336 if (interrupted)
2337 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002338
2339 if (done && !draining) {
2340 perf_evlist__disable(evlist);
2341 draining = true;
2342 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002343 }
2344 }
2345
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002346 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002347 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002348
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002349 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2350 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2351 draining = true;
2352
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002353 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002354 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002355 } else {
2356 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002357 }
2358
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002359out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002360 thread__zput(trace->current);
2361
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002362 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002363
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002364 if (!err) {
2365 if (trace->summary)
2366 trace__fprintf_thread_summary(trace, trace->output);
2367
2368 if (trace->show_tool_stats) {
2369 fprintf(trace->output, "Stats:\n "
2370 " vfs_getname : %" PRIu64 "\n"
2371 " proc_getname: %" PRIu64 "\n",
2372 trace->stats.vfs_getname,
2373 trace->stats.proc_getname);
2374 }
2375 }
David Ahernbf2575c2013-10-08 21:26:53 -06002376
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002377out_delete_evlist:
2378 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002379 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002380 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002381 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002382{
2383 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002384
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002385out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002386 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002387 goto out_error;
2388
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002389out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002390 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002391 goto out_error;
2392
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002393out_error_mmap:
2394 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2395 goto out_error;
2396
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002397out_error_open:
2398 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2399
2400out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002401 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302402 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002403
2404out_error_apply_filters:
2405 fprintf(trace->output,
2406 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2407 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002408 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002409 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002410}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002411out_error_mem:
2412 fprintf(trace->output, "Not enough memory to run!\n");
2413 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002414
2415out_errno:
2416 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2417 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002418}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002419
David Ahern6810fc92013-08-28 22:29:52 -06002420static int trace__replay(struct trace *trace)
2421{
2422 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002423 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002424 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002425 struct perf_data_file file = {
2426 .path = input_name,
2427 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002428 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002429 };
David Ahern6810fc92013-08-28 22:29:52 -06002430 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002431 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002432 int err = -1;
2433
2434 trace->tool.sample = trace__process_sample;
2435 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002436 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002437 trace->tool.comm = perf_event__process_comm;
2438 trace->tool.exit = perf_event__process_exit;
2439 trace->tool.fork = perf_event__process_fork;
2440 trace->tool.attr = perf_event__process_attr;
2441 trace->tool.tracing_data = perf_event__process_tracing_data;
2442 trace->tool.build_id = perf_event__process_build_id;
2443
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002444 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002445 trace->tool.ordering_requires_timestamps = true;
2446
2447 /* add tid to output */
2448 trace->multiple_threads = true;
2449
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002450 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002451 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002452 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002453
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002454 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002455 goto out;
2456
David Ahern8fb598e2013-09-28 13:13:00 -06002457 trace->host = &session->machines.host;
2458
David Ahern6810fc92013-08-28 22:29:52 -06002459 err = perf_session__set_tracepoints_handlers(session, handlers);
2460 if (err)
2461 goto out;
2462
Namhyung Kim003824e2013-11-12 15:25:00 +09002463 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2464 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002465 /* older kernels have syscalls tp versus raw_syscalls */
2466 if (evsel == NULL)
2467 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2468 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002469
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002470 if (evsel &&
2471 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2472 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002473 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2474 goto out;
2475 }
2476
2477 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2478 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002479 if (evsel == NULL)
2480 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2481 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002482 if (evsel &&
2483 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2484 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002485 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002486 goto out;
2487 }
2488
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002489 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002490 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2491 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2492 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2493 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2494 evsel->handler = trace__pgfault;
2495 }
2496
David Ahernbdc89662013-08-28 22:29:53 -06002497 err = parse_target_str(trace);
2498 if (err != 0)
2499 goto out;
2500
David Ahern6810fc92013-08-28 22:29:52 -06002501 setup_pager();
2502
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002503 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002504 if (err)
2505 pr_err("Failed to process events, error %d", err);
2506
David Ahernbf2575c2013-10-08 21:26:53 -06002507 else if (trace->summary)
2508 trace__fprintf_thread_summary(trace, trace->output);
2509
David Ahern6810fc92013-08-28 22:29:52 -06002510out:
2511 perf_session__delete(session);
2512
2513 return err;
2514}
2515
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002516static size_t trace__fprintf_threads_header(FILE *fp)
2517{
2518 size_t printed;
2519
Pekka Enberg99ff7152013-11-12 16:42:14 +02002520 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002521
2522 return printed;
2523}
2524
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002525DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2526 struct stats *stats;
2527 double msecs;
2528 int syscall;
2529)
2530{
2531 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2532 struct stats *stats = source->priv;
2533
2534 entry->syscall = source->i;
2535 entry->stats = stats;
2536 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2537}
2538
David Ahernbf2575c2013-10-08 21:26:53 -06002539static size_t thread__dump_stats(struct thread_trace *ttrace,
2540 struct trace *trace, FILE *fp)
2541{
David Ahernbf2575c2013-10-08 21:26:53 -06002542 size_t printed = 0;
2543 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002544 struct rb_node *nd;
2545 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002546
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002547 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002548 return 0;
2549
2550 printed += fprintf(fp, "\n");
2551
Milian Wolff834fd462015-08-06 11:24:29 +02002552 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2553 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2554 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002555
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002556 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002557 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002558 if (stats) {
2559 double min = (double)(stats->min) / NSEC_PER_MSEC;
2560 double max = (double)(stats->max) / NSEC_PER_MSEC;
2561 double avg = avg_stats(stats);
2562 double pct;
2563 u64 n = (u64) stats->n;
2564
2565 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2566 avg /= NSEC_PER_MSEC;
2567
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002568 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002569 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002570 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002571 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002572 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002573 }
David Ahernbf2575c2013-10-08 21:26:53 -06002574 }
2575
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002576 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002577 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002578
2579 return printed;
2580}
2581
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002582static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002583{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002584 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002585 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002586 double ratio;
2587
2588 if (ttrace == NULL)
2589 return 0;
2590
2591 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2592
Pekka Enberg15e65c62013-11-14 18:43:30 +02002593 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002594 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002595 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002596 if (ttrace->pfmaj)
2597 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2598 if (ttrace->pfmin)
2599 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002600 if (trace->sched)
2601 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2602 else if (fputc('\n', fp) != EOF)
2603 ++printed;
2604
David Ahernbf2575c2013-10-08 21:26:53 -06002605 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002606
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002607 return printed;
2608}
David Ahern896cbb52013-09-28 13:12:59 -06002609
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002610static unsigned long thread__nr_events(struct thread_trace *ttrace)
2611{
2612 return ttrace ? ttrace->nr_events : 0;
2613}
2614
2615DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2616 struct thread *thread;
2617)
2618{
2619 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002620}
2621
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002622static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2623{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002624 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2625 size_t printed = trace__fprintf_threads_header(fp);
2626 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002627
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002628 if (threads == NULL) {
2629 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2630 return 0;
2631 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002632
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002633 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002634 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2635
2636 resort_rb__delete(threads);
2637
2638 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002639}
2640
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002641static int trace__set_duration(const struct option *opt, const char *str,
2642 int unset __maybe_unused)
2643{
2644 struct trace *trace = opt->value;
2645
2646 trace->duration_filter = atof(str);
2647 return 0;
2648}
2649
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002650static int trace__set_filter_pids(const struct option *opt, const char *str,
2651 int unset __maybe_unused)
2652{
2653 int ret = -1;
2654 size_t i;
2655 struct trace *trace = opt->value;
2656 /*
2657 * FIXME: introduce a intarray class, plain parse csv and create a
2658 * { int nr, int entries[] } struct...
2659 */
2660 struct intlist *list = intlist__new(str);
2661
2662 if (list == NULL)
2663 return -1;
2664
2665 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2666 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2667
2668 if (trace->filter_pids.entries == NULL)
2669 goto out;
2670
2671 trace->filter_pids.entries[0] = getpid();
2672
2673 for (i = 1; i < trace->filter_pids.nr; ++i)
2674 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2675
2676 intlist__delete(list);
2677 ret = 0;
2678out:
2679 return ret;
2680}
2681
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002682static int trace__open_output(struct trace *trace, const char *filename)
2683{
2684 struct stat st;
2685
2686 if (!stat(filename, &st) && st.st_size) {
2687 char oldname[PATH_MAX];
2688
2689 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2690 unlink(oldname);
2691 rename(filename, oldname);
2692 }
2693
2694 trace->output = fopen(filename, "w");
2695
2696 return trace->output == NULL ? -errno : 0;
2697}
2698
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002699static int parse_pagefaults(const struct option *opt, const char *str,
2700 int unset __maybe_unused)
2701{
2702 int *trace_pgfaults = opt->value;
2703
2704 if (strcmp(str, "all") == 0)
2705 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2706 else if (strcmp(str, "maj") == 0)
2707 *trace_pgfaults |= TRACE_PFMAJ;
2708 else if (strcmp(str, "min") == 0)
2709 *trace_pgfaults |= TRACE_PFMIN;
2710 else
2711 return -1;
2712
2713 return 0;
2714}
2715
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002716static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2717{
2718 struct perf_evsel *evsel;
2719
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002720 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002721 evsel->handler = handler;
2722}
2723
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002724int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2725{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002726 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002727 "perf trace [<options>] [<command>]",
2728 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002729 "perf trace record [<options>] [<command>]",
2730 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002731 NULL
2732 };
2733 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002734 .syscalls = {
2735 . max = -1,
2736 },
2737 .opts = {
2738 .target = {
2739 .uid = UINT_MAX,
2740 .uses_mmap = true,
2741 },
2742 .user_freq = UINT_MAX,
2743 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002744 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002745 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002746 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002747 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002748 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002749 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002750 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002751 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002752 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002753 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002754 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002755 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002756 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002757 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2758 "event selector. use 'perf list' to list available events",
2759 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002760 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2761 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002762 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002763 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002764 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002765 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002766 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2767 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002768 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002769 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002770 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2771 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002772 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002773 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002774 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002775 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002776 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002777 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002778 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2779 "number of mmap data pages",
2780 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002781 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002782 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002783 OPT_CALLBACK(0, "duration", &trace, "float",
2784 "show only events with duration > N.M ms",
2785 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002786 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002787 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002788 OPT_BOOLEAN('T', "time", &trace.full_time,
2789 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002790 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2791 "Show only syscall summary with statistics"),
2792 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2793 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002794 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2795 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002796 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002797 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002798 OPT_CALLBACK(0, "call-graph", &trace.opts,
2799 "record_mode[,record_size]", record_callchain_help,
2800 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002801 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2802 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002803 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2804 "Set the minimum stack depth when parsing the callchain, "
2805 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002806 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2807 "Set the maximum stack depth when parsing the callchain, "
2808 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002809 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002810 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2811 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002812 OPT_END()
2813 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002814 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002815 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002816 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002817 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002818 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002819
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002820 signal(SIGSEGV, sighandler_dump_stack);
2821 signal(SIGFPE, sighandler_dump_stack);
2822
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002823 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002824 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002825
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002826 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002827 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002828 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002829 goto out;
2830 }
2831
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002832 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2833 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002834
Wang Nand7888572016-04-08 15:07:24 +00002835 err = bpf__setup_stdout(trace.evlist);
2836 if (err) {
2837 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2838 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2839 goto out;
2840 }
2841
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002842 err = -1;
2843
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002844 if (trace.trace_pgfaults) {
2845 trace.opts.sample_address = true;
2846 trace.opts.sample_time = true;
2847 }
2848
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002849 if (trace.opts.mmap_pages == UINT_MAX)
2850 mmap_pages_user_set = false;
2851
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002852 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002853 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002854 max_stack_user_set = false;
2855 }
2856
2857#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002858 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002859 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2860#endif
2861
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002862 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002863 if (!mmap_pages_user_set && geteuid() == 0)
2864 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2865
Milian Wolff566a0882016-04-08 13:34:15 +02002866 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002867 }
Milian Wolff566a0882016-04-08 13:34:15 +02002868
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002869 if (trace.evlist->nr_entries > 0)
2870 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2871
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002872 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2873 return trace__record(&trace, argc-1, &argv[1]);
2874
2875 /* summary_only implies summary option, but don't overwrite summary if set */
2876 if (trace.summary_only)
2877 trace.summary = trace.summary_only;
2878
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002879 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2880 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002881 pr_err("Please specify something to trace.\n");
2882 return -1;
2883 }
2884
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002885 if (!trace.trace_syscalls && ev_qualifier_str) {
2886 pr_err("The -e option can't be used with --no-syscalls.\n");
2887 goto out;
2888 }
2889
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002890 if (output_name != NULL) {
2891 err = trace__open_output(&trace, output_name);
2892 if (err < 0) {
2893 perror("failed to create output file");
2894 goto out;
2895 }
2896 }
2897
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002898 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2899
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002900 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002901 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002902 struct strlist_config slist_config = {
2903 .dirname = system_path(STRACE_GROUPS_DIR),
2904 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002905
2906 trace.not_ev_qualifier = *s == '!';
2907 if (trace.not_ev_qualifier)
2908 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002909 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002910 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002911 fputs("Not enough memory to parse event qualifier",
2912 trace.output);
2913 err = -ENOMEM;
2914 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002915 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002916
2917 err = trace__validate_ev_qualifier(&trace);
2918 if (err)
2919 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002920 }
2921
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002922 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002923 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002924 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002925 fprintf(trace.output, "%s", bf);
2926 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002927 }
2928
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002929 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002930 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002931 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002932 fprintf(trace.output, "%s", bf);
2933 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002934 }
2935
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002936 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002937 trace.opts.target.system_wide = true;
2938
David Ahern6810fc92013-08-28 22:29:52 -06002939 if (input_name)
2940 err = trace__replay(&trace);
2941 else
2942 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002943
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002944out_close:
2945 if (output_name != NULL)
2946 fclose(trace.output);
2947out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002948 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002949}