blob: 570a78c706c2da0b8d7afe7046bd79748262362f [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/filter.h>
45#include <linux/audit.h>
46#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030047#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030048#include <linux/stringify.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030049
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030050#ifndef O_CLOEXEC
51# define O_CLOEXEC 02000000
52#endif
53
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030054struct trace {
55 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030056 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030057 struct {
58 int max;
59 struct syscall *table;
60 struct {
61 struct perf_evsel *sys_enter,
62 *sys_exit;
63 } events;
64 } syscalls;
65 struct record_opts opts;
66 struct perf_evlist *evlist;
67 struct machine *host;
68 struct thread *current;
69 u64 base_time;
70 FILE *output;
71 unsigned long nr_events;
72 struct strlist *ev_qualifier;
73 struct {
74 size_t nr;
75 int *entries;
76 } ev_qualifier_ids;
77 struct intlist *tid_list;
78 struct intlist *pid_list;
79 struct {
80 size_t nr;
81 pid_t *entries;
82 } filter_pids;
83 double duration_filter;
84 double runtime_ms;
85 struct {
86 u64 vfs_getname,
87 proc_getname;
88 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030089 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030090 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030091 bool not_ev_qualifier;
92 bool live;
93 bool full_time;
94 bool sched;
95 bool multiple_threads;
96 bool summary;
97 bool summary_only;
98 bool show_comm;
99 bool show_tool_stats;
100 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300101 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300102 bool force;
103 bool vfs_getname;
104 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300105 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300107
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300108struct tp_field {
109 int offset;
110 union {
111 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
112 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
113 };
114};
115
116#define TP_UINT_FIELD(bits) \
117static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
118{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500119 u##bits value; \
120 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
121 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300122}
123
124TP_UINT_FIELD(8);
125TP_UINT_FIELD(16);
126TP_UINT_FIELD(32);
127TP_UINT_FIELD(64);
128
129#define TP_UINT_FIELD__SWAPPED(bits) \
130static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
131{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500132 u##bits value; \
133 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300134 return bswap_##bits(value);\
135}
136
137TP_UINT_FIELD__SWAPPED(16);
138TP_UINT_FIELD__SWAPPED(32);
139TP_UINT_FIELD__SWAPPED(64);
140
141static int tp_field__init_uint(struct tp_field *field,
142 struct format_field *format_field,
143 bool needs_swap)
144{
145 field->offset = format_field->offset;
146
147 switch (format_field->size) {
148 case 1:
149 field->integer = tp_field__u8;
150 break;
151 case 2:
152 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
153 break;
154 case 4:
155 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
156 break;
157 case 8:
158 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
159 break;
160 default:
161 return -1;
162 }
163
164 return 0;
165}
166
167static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
168{
169 return sample->raw_data + field->offset;
170}
171
172static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
173{
174 field->offset = format_field->offset;
175 field->pointer = tp_field__ptr;
176 return 0;
177}
178
179struct syscall_tp {
180 struct tp_field id;
181 union {
182 struct tp_field args, ret;
183 };
184};
185
186static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
187 struct tp_field *field,
188 const char *name)
189{
190 struct format_field *format_field = perf_evsel__field(evsel, name);
191
192 if (format_field == NULL)
193 return -1;
194
195 return tp_field__init_uint(field, format_field, evsel->needs_swap);
196}
197
198#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
199 ({ struct syscall_tp *sc = evsel->priv;\
200 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
201
202static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
203 struct tp_field *field,
204 const char *name)
205{
206 struct format_field *format_field = perf_evsel__field(evsel, name);
207
208 if (format_field == NULL)
209 return -1;
210
211 return tp_field__init_ptr(field, format_field);
212}
213
214#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
215 ({ struct syscall_tp *sc = evsel->priv;\
216 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
217
218static void perf_evsel__delete_priv(struct perf_evsel *evsel)
219{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300220 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300221 perf_evsel__delete(evsel);
222}
223
Namhyung Kim96695d42013-11-12 08:51:45 -0300224static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
225{
226 evsel->priv = malloc(sizeof(struct syscall_tp));
227 if (evsel->priv != NULL) {
228 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
229 goto out_delete;
230
231 evsel->handler = handler;
232 return 0;
233 }
234
235 return -ENOMEM;
236
237out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300238 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300239 return -ENOENT;
240}
241
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300242static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300243{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245
David Ahern9aca7f12013-12-04 19:41:39 -0700246 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200247 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700248 evsel = perf_evsel__newtp("syscalls", direction);
249
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200250 if (IS_ERR(evsel))
251 return NULL;
252
253 if (perf_evsel__init_syscall_tp(evsel, handler))
254 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300255
256 return evsel;
257
258out_delete:
259 perf_evsel__delete_priv(evsel);
260 return NULL;
261}
262
263#define perf_evsel__sc_tp_uint(evsel, name, sample) \
264 ({ struct syscall_tp *fields = evsel->priv; \
265 fields->name.integer(&fields->name, sample); })
266
267#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
268 ({ struct syscall_tp *fields = evsel->priv; \
269 fields->name.pointer(&fields->name, sample); })
270
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271struct syscall_arg {
272 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300273 struct thread *thread;
274 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300275 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300276 u8 idx;
277 u8 mask;
278};
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300281 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282 int nr_entries;
283 const char **entries;
284};
285
286#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
287 .nr_entries = ARRAY_SIZE(array), \
288 .entries = array, \
289}
290
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300291#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
292 .offset = off, \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300297static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
298 const char *intfmt,
299 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300302 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303
304 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300305 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306
307 return scnprintf(bf, size, "%s", sa->entries[idx]);
308}
309
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300310static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
311 struct syscall_arg *arg)
312{
313 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
314}
315
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316#define SCA_STRARRAY syscall_arg__scnprintf_strarray
317
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300318#if defined(__i386__) || defined(__x86_64__)
319/*
320 * FIXME: Make this available to all arches as soon as the ioctl beautifier
321 * gets rewritten to support all arches.
322 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300323static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
324 struct syscall_arg *arg)
325{
326 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
327}
328
329#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300330#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300331
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300332static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
333 struct syscall_arg *arg);
334
335#define SCA_FD syscall_arg__scnprintf_fd
336
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300337#ifndef AT_FDCWD
338#define AT_FDCWD -100
339#endif
340
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300341static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
342 struct syscall_arg *arg)
343{
344 int fd = arg->val;
345
346 if (fd == AT_FDCWD)
347 return scnprintf(bf, size, "CWD");
348
349 return syscall_arg__scnprintf_fd(bf, size, arg);
350}
351
352#define SCA_FDAT syscall_arg__scnprintf_fd_at
353
354static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
355 struct syscall_arg *arg);
356
357#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
358
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300359static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300360 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300361{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300362 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300363}
364
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300365#define SCA_HEX syscall_arg__scnprintf_hex
366
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300367static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
368 struct syscall_arg *arg)
369{
370 return scnprintf(bf, size, "%d", arg->val);
371}
372
373#define SCA_INT syscall_arg__scnprintf_int
374
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300375static const char *bpf_cmd[] = {
376 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
377 "MAP_GET_NEXT_KEY", "PROG_LOAD",
378};
379static DEFINE_STRARRAY(bpf_cmd);
380
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300381static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
382static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300383
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300384static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
385static DEFINE_STRARRAY(itimers);
386
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300387static const char *keyctl_options[] = {
388 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
389 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
390 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
391 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
392 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
393};
394static DEFINE_STRARRAY(keyctl_options);
395
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300396static const char *whences[] = { "SET", "CUR", "END",
397#ifdef SEEK_DATA
398"DATA",
399#endif
400#ifdef SEEK_HOLE
401"HOLE",
402#endif
403};
404static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300405
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300406static const char *fcntl_cmds[] = {
407 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
408 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
409 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
410 "F_GETOWNER_UIDS",
411};
412static DEFINE_STRARRAY(fcntl_cmds);
413
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300414static const char *rlimit_resources[] = {
415 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
416 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
417 "RTTIME",
418};
419static DEFINE_STRARRAY(rlimit_resources);
420
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300421static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
422static DEFINE_STRARRAY(sighow);
423
David Ahern4f8c1b72013-09-22 19:45:00 -0600424static const char *clockid[] = {
425 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300426 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
427 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600428};
429static DEFINE_STRARRAY(clockid);
430
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300431static const char *socket_families[] = {
432 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
433 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
434 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
435 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
436 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
437 "ALG", "NFC", "VSOCK",
438};
439static DEFINE_STRARRAY(socket_families);
440
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300441static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
442 struct syscall_arg *arg)
443{
444 size_t printed = 0;
445 int mode = arg->val;
446
447 if (mode == F_OK) /* 0 */
448 return scnprintf(bf, size, "F");
449#define P_MODE(n) \
450 if (mode & n##_OK) { \
451 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
452 mode &= ~n##_OK; \
453 }
454
455 P_MODE(R);
456 P_MODE(W);
457 P_MODE(X);
458#undef P_MODE
459
460 if (mode)
461 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
462
463 return printed;
464}
465
466#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
467
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300468static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
469 struct syscall_arg *arg);
470
471#define SCA_FILENAME syscall_arg__scnprintf_filename
472
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300473static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
474 struct syscall_arg *arg)
475{
476 int printed = 0, flags = arg->val;
477
478#define P_FLAG(n) \
479 if (flags & O_##n) { \
480 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
481 flags &= ~O_##n; \
482 }
483
484 P_FLAG(CLOEXEC);
485 P_FLAG(NONBLOCK);
486#undef P_FLAG
487
488 if (flags)
489 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
490
491 return printed;
492}
493
494#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
495
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300496#if defined(__i386__) || defined(__x86_64__)
497/*
498 * FIXME: Make this available to all arches.
499 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300500#define TCGETS 0x5401
501
502static const char *tioctls[] = {
503 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
504 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
505 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
506 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
507 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
508 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
509 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
510 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
511 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
512 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
513 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
514 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
515 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
516 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
517 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
518};
519
520static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300521#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300522
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300523#ifndef GRND_NONBLOCK
524#define GRND_NONBLOCK 0x0001
525#endif
526#ifndef GRND_RANDOM
527#define GRND_RANDOM 0x0002
528#endif
529
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300530static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
531 struct syscall_arg *arg)
532{
533 int printed = 0, flags = arg->val;
534
535#define P_FLAG(n) \
536 if (flags & GRND_##n) { \
537 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
538 flags &= ~GRND_##n; \
539 }
540
541 P_FLAG(RANDOM);
542 P_FLAG(NONBLOCK);
543#undef P_FLAG
544
545 if (flags)
546 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
547
548 return printed;
549}
550
551#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
552
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300553#define STRARRAY(arg, name, array) \
554 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
555 .arg_parm = { [arg] = &strarray__##array, }
556
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300557#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300558#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300559#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300560#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300561#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300562#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300563#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300564#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300565#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300566#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300567#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300568#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300569#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300570#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300571
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300572static struct syscall_fmt {
573 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300574 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300575 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300576 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300577 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300578 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300579 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300580 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300581} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300582 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300583 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300584 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300585 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300586 { .name = "brk", .hexret = true,
587 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300588 { .name = "chdir", .errmsg = true, },
589 { .name = "chmod", .errmsg = true, },
590 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600591 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300592 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300593 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300594 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300595 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300596 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300597 { .name = "dup", .errmsg = true, },
598 { .name = "dup2", .errmsg = true, },
599 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300600 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300601 { .name = "eventfd2", .errmsg = true,
602 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300603 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300604 { .name = "fadvise64", .errmsg = true, },
605 { .name = "fallocate", .errmsg = true, },
606 { .name = "fchdir", .errmsg = true, },
607 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300608 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300609 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300610 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300611 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300612 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300613 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300614 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300615 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300616 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300617 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300618 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
619 { .name = "fsetxattr", .errmsg = true, },
620 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300621 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300622 { .name = "fstatfs", .errmsg = true, },
623 { .name = "fsync", .errmsg = true, },
624 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300625 { .name = "futex", .errmsg = true,
626 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300627 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300628 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300629 { .name = "getdents", .errmsg = true, },
630 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300631 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300632 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300633 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300634 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300635 { .name = "getrandom", .errmsg = true,
636 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300637 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300638 { .name = "getxattr", .errmsg = true, },
639 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300640 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300641 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300642#if defined(__i386__) || defined(__x86_64__)
643/*
644 * FIXME: Make this available to all arches.
645 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300646 [1] = SCA_STRHEXARRAY, /* cmd */
647 [2] = SCA_HEX, /* arg */ },
648 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300649#else
650 [2] = SCA_HEX, /* arg */ }, },
651#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300652 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300653 { .name = "kill", .errmsg = true,
654 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300655 { .name = "lchown", .errmsg = true, },
656 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300657 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300658 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300659 { .name = "listxattr", .errmsg = true, },
660 { .name = "llistxattr", .errmsg = true, },
661 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300662 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300663 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300664 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300665 { .name = "lsetxattr", .errmsg = true, },
666 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
667 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300668 { .name = "madvise", .errmsg = true,
669 .arg_scnprintf = { [0] = SCA_HEX, /* start */
670 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300671 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300672 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300673 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
674 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300675 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300676 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300677 { .name = "mlock", .errmsg = true,
678 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
679 { .name = "mlockall", .errmsg = true,
680 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300681 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300682 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300683 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300684 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300685 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300686 .arg_scnprintf = { [0] = SCA_HEX, /* start */
687 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300688 { .name = "mq_unlink", .errmsg = true,
689 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300690 { .name = "mremap", .hexret = true,
691 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300692 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300693 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300694 { .name = "munlock", .errmsg = true,
695 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300696 { .name = "munmap", .errmsg = true,
697 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300698 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300699 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300700 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300701 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300702 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300703 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300704 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300705 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
706 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300707 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300708 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
709 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300710 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300711 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300712 [3] = SCA_FD, /* group_fd */
713 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300714 { .name = "pipe2", .errmsg = true,
715 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300716 { .name = "poll", .errmsg = true, .timeout = true, },
717 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300718 { .name = "pread", .errmsg = true, .alias = "pread64", },
719 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300720 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300721 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
722 { .name = "pwritev", .errmsg = true, },
723 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300724 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300725 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300726 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300727 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300728 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300729 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300730 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300731 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300732 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300733 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300734 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300735 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300736 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300737 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300738 { .name = "rt_sigaction", .errmsg = true,
739 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300740 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300741 { .name = "rt_sigqueueinfo", .errmsg = true,
742 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
743 { .name = "rt_tgsigqueueinfo", .errmsg = true,
744 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300745 { .name = "sched_setscheduler", .errmsg = true,
746 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300747 { .name = "seccomp", .errmsg = true,
748 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
749 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300750 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300751 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300752 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300753 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300754 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300755 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300756 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300757 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300758 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300759 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300760 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300761 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300762 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300763 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300764 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
765 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300766 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300767 { .name = "socketpair", .errmsg = true,
768 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
769 [1] = SCA_SK_TYPE, /* type */ },
770 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300771 { .name = "stat", .errmsg = true, .alias = "newstat", },
772 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300773 { .name = "swapoff", .errmsg = true,
774 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
775 { .name = "swapon", .errmsg = true,
776 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300777 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300778 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300779 { .name = "tgkill", .errmsg = true,
780 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
781 { .name = "tkill", .errmsg = true,
782 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300783 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300784 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300785 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300786 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
787 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300788 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300789 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
790 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300791 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300792 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300793 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300794 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300795 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300796 { .name = "write", .errmsg = true, },
797 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300798};
799
800static int syscall_fmt__cmp(const void *name, const void *fmtp)
801{
802 const struct syscall_fmt *fmt = fmtp;
803 return strcmp(name, fmt->name);
804}
805
806static struct syscall_fmt *syscall_fmt__find(const char *name)
807{
808 const int nmemb = ARRAY_SIZE(syscall_fmts);
809 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
810}
811
812struct syscall {
813 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300814 int nr_args;
815 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300816 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300817 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300818 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300819 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300820 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300821};
822
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200823static size_t fprintf_duration(unsigned long t, FILE *fp)
824{
825 double duration = (double)t / NSEC_PER_MSEC;
826 size_t printed = fprintf(fp, "(");
827
828 if (duration >= 1.0)
829 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
830 else if (duration >= 0.01)
831 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
832 else
833 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300834 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200835}
836
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300837/**
838 * filename.ptr: The filename char pointer that will be vfs_getname'd
839 * filename.entry_str_pos: Where to insert the string translated from
840 * filename.ptr by the vfs_getname tracepoint/kprobe.
841 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300842struct thread_trace {
843 u64 entry_time;
844 u64 exit_time;
845 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300846 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400847 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300848 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300849 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300850 struct {
851 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300852 short int entry_str_pos;
853 bool pending_open;
854 unsigned int namelen;
855 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300856 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300857 struct {
858 int max;
859 char **table;
860 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600861
862 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300863};
864
865static struct thread_trace *thread_trace__new(void)
866{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300867 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
868
869 if (ttrace)
870 ttrace->paths.max = -1;
871
David Ahernbf2575c2013-10-08 21:26:53 -0600872 ttrace->syscall_stats = intlist__new(NULL);
873
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300874 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300875}
876
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300877static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300878{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300879 struct thread_trace *ttrace;
880
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300881 if (thread == NULL)
882 goto fail;
883
Namhyung Kim89dceb22014-10-06 09:46:03 +0900884 if (thread__priv(thread) == NULL)
885 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300886
Namhyung Kim89dceb22014-10-06 09:46:03 +0900887 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300888 goto fail;
889
Namhyung Kim89dceb22014-10-06 09:46:03 +0900890 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300891 ++ttrace->nr_events;
892
893 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300894fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300895 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300896 "WARNING: not enough memory, dropping samples!\n");
897 return NULL;
898}
899
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400900#define TRACE_PFMAJ (1 << 0)
901#define TRACE_PFMIN (1 << 1)
902
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300903static const size_t trace__entry_str_size = 2048;
904
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300905static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300906{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900907 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908
909 if (fd > ttrace->paths.max) {
910 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
911
912 if (npath == NULL)
913 return -1;
914
915 if (ttrace->paths.max != -1) {
916 memset(npath + ttrace->paths.max + 1, 0,
917 (fd - ttrace->paths.max) * sizeof(char *));
918 } else {
919 memset(npath, 0, (fd + 1) * sizeof(char *));
920 }
921
922 ttrace->paths.table = npath;
923 ttrace->paths.max = fd;
924 }
925
926 ttrace->paths.table[fd] = strdup(pathname);
927
928 return ttrace->paths.table[fd] != NULL ? 0 : -1;
929}
930
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300931static int thread__read_fd_path(struct thread *thread, int fd)
932{
933 char linkname[PATH_MAX], pathname[PATH_MAX];
934 struct stat st;
935 int ret;
936
937 if (thread->pid_ == thread->tid) {
938 scnprintf(linkname, sizeof(linkname),
939 "/proc/%d/fd/%d", thread->pid_, fd);
940 } else {
941 scnprintf(linkname, sizeof(linkname),
942 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
943 }
944
945 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
946 return -1;
947
948 ret = readlink(linkname, pathname, sizeof(pathname));
949
950 if (ret < 0 || ret > st.st_size)
951 return -1;
952
953 pathname[ret] = '\0';
954 return trace__set_fd_pathname(thread, fd, pathname);
955}
956
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300957static const char *thread__fd_path(struct thread *thread, int fd,
958 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300959{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900960 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300961
962 if (ttrace == NULL)
963 return NULL;
964
965 if (fd < 0)
966 return NULL;
967
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300968 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300969 if (!trace->live)
970 return NULL;
971 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300972 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300973 return NULL;
974 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975
976 return ttrace->paths.table[fd];
977}
978
979static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
980 struct syscall_arg *arg)
981{
982 int fd = arg->val;
983 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300984 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985
986 if (path)
987 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
988
989 return printed;
990}
991
992static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
993 struct syscall_arg *arg)
994{
995 int fd = arg->val;
996 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +0900997 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300998
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300999 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1000 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001001
1002 return printed;
1003}
1004
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001005static void thread__set_filename_pos(struct thread *thread, const char *bf,
1006 unsigned long ptr)
1007{
1008 struct thread_trace *ttrace = thread__priv(thread);
1009
1010 ttrace->filename.ptr = ptr;
1011 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1012}
1013
1014static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1015 struct syscall_arg *arg)
1016{
1017 unsigned long ptr = arg->val;
1018
1019 if (!arg->trace->vfs_getname)
1020 return scnprintf(bf, size, "%#x", ptr);
1021
1022 thread__set_filename_pos(arg->thread, bf, ptr);
1023 return 0;
1024}
1025
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001026static bool trace__filter_duration(struct trace *trace, double t)
1027{
1028 return t < (trace->duration_filter * NSEC_PER_MSEC);
1029}
1030
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001031static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1032{
1033 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1034
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001035 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001036}
1037
Namhyung Kimf15eb532012-10-05 14:02:16 +09001038static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001039static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001040
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001041static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001042{
1043 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001044 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001045}
1046
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001047static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001048 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001049{
1050 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001051 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001052
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001053 if (trace->multiple_threads) {
1054 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001055 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001056 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001057 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001058
1059 return printed;
1060}
1061
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001062static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001063 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001064{
1065 int ret = 0;
1066
1067 switch (event->header.type) {
1068 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001069 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001070 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001071 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001072 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001073 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001074 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001075 break;
1076 }
1077
1078 return ret;
1079}
1080
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001081static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001082 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001083 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084 struct machine *machine)
1085{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001086 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001087 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001088}
1089
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001090static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1091{
1092 struct machine *machine = vmachine;
1093
1094 if (machine->kptr_restrict_warned)
1095 return NULL;
1096
1097 if (symbol_conf.kptr_restrict) {
1098 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1099 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1100 "Kernel samples will not be resolved.\n");
1101 machine->kptr_restrict_warned = true;
1102 return NULL;
1103 }
1104
1105 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1106}
1107
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001108static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1109{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001110 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111
1112 if (err)
1113 return err;
1114
David Ahern8fb598e2013-09-28 13:13:00 -06001115 trace->host = machine__new_host();
1116 if (trace->host == NULL)
1117 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001118
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001119 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001120 return -errno;
1121
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001122 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001123 evlist->threads, trace__tool_process, false,
1124 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125 if (err)
1126 symbol__exit();
1127
1128 return err;
1129}
1130
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001131static int syscall__set_arg_fmts(struct syscall *sc)
1132{
1133 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001134 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001135
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001136 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001137 if (sc->arg_scnprintf == NULL)
1138 return -1;
1139
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001140 if (sc->fmt)
1141 sc->arg_parm = sc->fmt->arg_parm;
1142
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001143 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001144 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1145 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001146 else if (strcmp(field->type, "const char *") == 0 &&
1147 (strcmp(field->name, "filename") == 0 ||
1148 strcmp(field->name, "path") == 0 ||
1149 strcmp(field->name, "pathname") == 0))
1150 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001151 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001152 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001153 else if (strcmp(field->type, "pid_t") == 0)
1154 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001155 else if (strcmp(field->type, "umode_t") == 0)
1156 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001157 else if ((strcmp(field->type, "int") == 0 ||
1158 strcmp(field->type, "unsigned int") == 0 ||
1159 strcmp(field->type, "long") == 0) &&
1160 (len = strlen(field->name)) >= 2 &&
1161 strcmp(field->name + len - 2, "fd") == 0) {
1162 /*
1163 * /sys/kernel/tracing/events/syscalls/sys_enter*
1164 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1165 * 65 int
1166 * 23 unsigned int
1167 * 7 unsigned long
1168 */
1169 sc->arg_scnprintf[idx] = SCA_FD;
1170 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001171 ++idx;
1172 }
1173
1174 return 0;
1175}
1176
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001177static int trace__read_syscall_info(struct trace *trace, int id)
1178{
1179 char tp_name[128];
1180 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001181 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001182
1183 if (name == NULL)
1184 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001185
1186 if (id > trace->syscalls.max) {
1187 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1188
1189 if (nsyscalls == NULL)
1190 return -1;
1191
1192 if (trace->syscalls.max != -1) {
1193 memset(nsyscalls + trace->syscalls.max + 1, 0,
1194 (id - trace->syscalls.max) * sizeof(*sc));
1195 } else {
1196 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1197 }
1198
1199 trace->syscalls.table = nsyscalls;
1200 trace->syscalls.max = id;
1201 }
1202
1203 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001204 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001205
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001206 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001207
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001208 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001209 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001210
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001211 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001212 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001213 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001214 }
1215
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001216 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001217 return -1;
1218
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001219 sc->args = sc->tp_format->format.fields;
1220 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001221 /*
1222 * We need to check and discard the first variable '__syscall_nr'
1223 * or 'nr' that mean the syscall number. It is needless here.
1224 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1225 */
1226 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001227 sc->args = sc->args->next;
1228 --sc->nr_args;
1229 }
1230
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001231 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1232
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001233 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001234}
1235
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001236static int trace__validate_ev_qualifier(struct trace *trace)
1237{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001238 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001239 struct str_node *pos;
1240
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001241 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1242 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1243 sizeof(trace->ev_qualifier_ids.entries[0]));
1244
1245 if (trace->ev_qualifier_ids.entries == NULL) {
1246 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1247 trace->output);
1248 err = -EINVAL;
1249 goto out;
1250 }
1251
1252 i = 0;
1253
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001254 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001255 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001256 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001257
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001258 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001259 if (err == 0) {
1260 fputs("Error:\tInvalid syscall ", trace->output);
1261 err = -EINVAL;
1262 } else {
1263 fputs(", ", trace->output);
1264 }
1265
1266 fputs(sc, trace->output);
1267 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001268
1269 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001270 }
1271
1272 if (err < 0) {
1273 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1274 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001275 zfree(&trace->ev_qualifier_ids.entries);
1276 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001277 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001278out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001279 return err;
1280}
1281
David Ahern55d43bc2015-02-19 15:00:22 -05001282/*
1283 * args is to be interpreted as a series of longs but we need to handle
1284 * 8-byte unaligned accesses. args points to raw_data within the event
1285 * and raw_data is guaranteed to be 8-byte unaligned because it is
1286 * preceded by raw_size which is a u32. So we need to copy args to a temp
1287 * variable to read it. Most notably this avoids extended load instructions
1288 * on unaligned addresses
1289 */
1290
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001291static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001292 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001293 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001294{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001295 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001296 unsigned char *p;
1297 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001298
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001299 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001300 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001301 u8 bit = 1;
1302 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001303 .idx = 0,
1304 .mask = 0,
1305 .trace = trace,
1306 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001307 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001308
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001309 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001310 field = field->next, ++arg.idx, bit <<= 1) {
1311 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001312 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001313
1314 /* special care for unaligned accesses */
1315 p = args + sizeof(unsigned long) * arg.idx;
1316 memcpy(&val, p, sizeof(val));
1317
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001318 /*
1319 * Suppress this argument if its value is zero and
1320 * and we don't have a string associated in an
1321 * strarray for it.
1322 */
David Ahern55d43bc2015-02-19 15:00:22 -05001323 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001324 !(sc->arg_scnprintf &&
1325 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1326 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001327 continue;
1328
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001329 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001330 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001331 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001332 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001333 if (sc->arg_parm)
1334 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001335 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1336 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001337 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001338 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001339 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001340 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001341 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001342 } else if (IS_ERR(sc->tp_format)) {
1343 /*
1344 * If we managed to read the tracepoint /format file, then we
1345 * may end up not having any args, like with gettid(), so only
1346 * print the raw args when we didn't manage to read it.
1347 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001348 int i = 0;
1349
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001350 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001351 /* special care for unaligned accesses */
1352 p = args + sizeof(unsigned long) * i;
1353 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001354 printed += scnprintf(bf + printed, size - printed,
1355 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001356 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001357 ++i;
1358 }
1359 }
1360
1361 return printed;
1362}
1363
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001364typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001365 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001366 struct perf_sample *sample);
1367
1368static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001369 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001370{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001371
1372 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001373
1374 /*
1375 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1376 * before that, leaving at a higher verbosity level till that is
1377 * explained. Reproduced with plain ftrace with:
1378 *
1379 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1380 * grep "NR -1 " /t/trace_pipe
1381 *
1382 * After generating some load on the machine.
1383 */
1384 if (verbose > 1) {
1385 static u64 n;
1386 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1387 id, perf_evsel__name(evsel), ++n);
1388 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001389 return NULL;
1390 }
1391
1392 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1393 trace__read_syscall_info(trace, id))
1394 goto out_cant_read;
1395
1396 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1397 goto out_cant_read;
1398
1399 return &trace->syscalls.table[id];
1400
1401out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001402 if (verbose) {
1403 fprintf(trace->output, "Problems reading syscall %d", id);
1404 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1405 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1406 fputs(" information\n", trace->output);
1407 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001408 return NULL;
1409}
1410
David Ahernbf2575c2013-10-08 21:26:53 -06001411static void thread__update_stats(struct thread_trace *ttrace,
1412 int id, struct perf_sample *sample)
1413{
1414 struct int_node *inode;
1415 struct stats *stats;
1416 u64 duration = 0;
1417
1418 inode = intlist__findnew(ttrace->syscall_stats, id);
1419 if (inode == NULL)
1420 return;
1421
1422 stats = inode->priv;
1423 if (stats == NULL) {
1424 stats = malloc(sizeof(struct stats));
1425 if (stats == NULL)
1426 return;
1427 init_stats(stats);
1428 inode->priv = stats;
1429 }
1430
1431 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1432 duration = sample->time - ttrace->entry_time;
1433
1434 update_stats(stats, duration);
1435}
1436
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001437static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1438{
1439 struct thread_trace *ttrace;
1440 u64 duration;
1441 size_t printed;
1442
1443 if (trace->current == NULL)
1444 return 0;
1445
1446 ttrace = thread__priv(trace->current);
1447
1448 if (!ttrace->entry_pending)
1449 return 0;
1450
1451 duration = sample->time - ttrace->entry_time;
1452
1453 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1454 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1455 ttrace->entry_pending = false;
1456
1457 return printed;
1458}
1459
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001460static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001461 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001462 struct perf_sample *sample)
1463{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001464 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001465 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001466 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001467 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001468 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001469 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001470 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001471
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001472 if (sc == NULL)
1473 return -1;
1474
David Ahern8fb598e2013-09-28 13:13:00 -06001475 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001476 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001477 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001478 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001479
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001480 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001481
1482 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001483 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001484 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001485 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001486 }
1487
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001488 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001489 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001490
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001491 ttrace->entry_time = sample->time;
1492 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001493 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001494
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001495 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001496 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001497
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001498 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001499 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001500 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001501 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001502 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001503 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001504 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001505 /* See trace__vfs_getname & trace__sys_exit */
1506 ttrace->filename.pending_open = false;
1507 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001508
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001509 if (trace->current != thread) {
1510 thread__put(trace->current);
1511 trace->current = thread__get(thread);
1512 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001513 err = 0;
1514out_put:
1515 thread__put(thread);
1516 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001517}
1518
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001519static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1520 struct perf_sample *sample,
1521 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001522{
1523 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001524
1525 if (machine__resolve(trace->host, &al, sample) < 0 ||
1526 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1527 return -1;
1528
1529 return 0;
1530}
1531
1532static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1533{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001534 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001535 const unsigned int print_opts = EVSEL__PRINT_SYM |
1536 EVSEL__PRINT_DSO |
1537 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001538
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001539 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001540}
1541
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001542static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001543 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001544 struct perf_sample *sample)
1545{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001546 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001547 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001548 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001549 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001550 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001551 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001552
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001553 if (sc == NULL)
1554 return -1;
1555
David Ahern8fb598e2013-09-28 13:13:00 -06001556 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001557 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001558 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001559 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001560
David Ahernbf2575c2013-10-08 21:26:53 -06001561 if (trace->summary)
1562 thread__update_stats(ttrace, id, sample);
1563
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001564 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001565
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001566 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001567 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1568 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001569 ++trace->stats.vfs_getname;
1570 }
1571
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001572 ttrace->exit_time = sample->time;
1573
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001574 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001575 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001576 if (trace__filter_duration(trace, duration))
1577 goto out;
1578 } else if (trace->duration_filter)
1579 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001580
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001581 if (sample->callchain) {
1582 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1583 if (callchain_ret == 0) {
1584 if (callchain_cursor.nr < trace->min_stack)
1585 goto out;
1586 callchain_ret = 1;
1587 }
1588 }
1589
David Ahernfd2eaba2013-11-12 09:31:15 -07001590 if (trace->summary_only)
1591 goto out;
1592
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001593 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001594
1595 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001596 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001597 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001598 fprintf(trace->output, " ... [");
1599 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1600 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001601 }
1602
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001603 if (sc->fmt == NULL) {
1604signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001605 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001606 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001607 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001608 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001609 *e = audit_errno_to_name(-ret);
1610
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001611 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001612 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001613 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001614 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001615 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001616 else if (sc->fmt->errpid) {
1617 struct thread *child = machine__find_thread(trace->host, ret, ret);
1618
1619 if (child != NULL) {
1620 fprintf(trace->output, ") = %ld", ret);
1621 if (child->comm_set)
1622 fprintf(trace->output, " (%s)", thread__comm_str(child));
1623 thread__put(child);
1624 }
1625 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001626 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001627
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001628 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001629
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001630 if (callchain_ret > 0)
1631 trace__fprintf_callchain(trace, sample);
1632 else if (callchain_ret < 0)
1633 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001634out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001635 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001636 err = 0;
1637out_put:
1638 thread__put(thread);
1639 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001640}
1641
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001642static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001643 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001644 struct perf_sample *sample)
1645{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001646 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1647 struct thread_trace *ttrace;
1648 size_t filename_len, entry_str_len, to_move;
1649 ssize_t remaining_space;
1650 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001651 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001652
1653 if (!thread)
1654 goto out;
1655
1656 ttrace = thread__priv(thread);
1657 if (!ttrace)
1658 goto out;
1659
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001660 filename_len = strlen(filename);
1661
1662 if (ttrace->filename.namelen < filename_len) {
1663 char *f = realloc(ttrace->filename.name, filename_len + 1);
1664
1665 if (f == NULL)
1666 goto out;
1667
1668 ttrace->filename.namelen = filename_len;
1669 ttrace->filename.name = f;
1670 }
1671
1672 strcpy(ttrace->filename.name, filename);
1673 ttrace->filename.pending_open = true;
1674
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001675 if (!ttrace->filename.ptr)
1676 goto out;
1677
1678 entry_str_len = strlen(ttrace->entry_str);
1679 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1680 if (remaining_space <= 0)
1681 goto out;
1682
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001683 if (filename_len > (size_t)remaining_space) {
1684 filename += filename_len - remaining_space;
1685 filename_len = remaining_space;
1686 }
1687
1688 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1689 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1690 memmove(pos + filename_len, pos, to_move);
1691 memcpy(pos, filename, filename_len);
1692
1693 ttrace->filename.ptr = 0;
1694 ttrace->filename.entry_str_pos = 0;
1695out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001696 return 0;
1697}
1698
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001699static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001700 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001701 struct perf_sample *sample)
1702{
1703 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1704 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001705 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001706 sample->pid,
1707 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001708 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001709
1710 if (ttrace == NULL)
1711 goto out_dump;
1712
1713 ttrace->runtime_ms += runtime_ms;
1714 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001715 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001716 return 0;
1717
1718out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001720 evsel->name,
1721 perf_evsel__strval(evsel, sample, "comm"),
1722 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1723 runtime,
1724 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001725 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001726 return 0;
1727}
1728
Wang Nan1d6c9402016-02-26 09:31:55 +00001729static void bpf_output__printer(enum binary_printer_ops op,
1730 unsigned int val, void *extra)
1731{
1732 FILE *output = extra;
1733 unsigned char ch = (unsigned char)val;
1734
1735 switch (op) {
1736 case BINARY_PRINT_CHAR_DATA:
1737 fprintf(output, "%c", isprint(ch) ? ch : '.');
1738 break;
1739 case BINARY_PRINT_DATA_BEGIN:
1740 case BINARY_PRINT_LINE_BEGIN:
1741 case BINARY_PRINT_ADDR:
1742 case BINARY_PRINT_NUM_DATA:
1743 case BINARY_PRINT_NUM_PAD:
1744 case BINARY_PRINT_SEP:
1745 case BINARY_PRINT_CHAR_PAD:
1746 case BINARY_PRINT_LINE_END:
1747 case BINARY_PRINT_DATA_END:
1748 default:
1749 break;
1750 }
1751}
1752
1753static void bpf_output__fprintf(struct trace *trace,
1754 struct perf_sample *sample)
1755{
1756 print_binary(sample->raw_data, sample->raw_size, 8,
1757 bpf_output__printer, trace->output);
1758}
1759
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001760static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1761 union perf_event *event __maybe_unused,
1762 struct perf_sample *sample)
1763{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001764 int callchain_ret = 0;
1765
1766 if (sample->callchain) {
1767 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1768 if (callchain_ret == 0) {
1769 if (callchain_cursor.nr < trace->min_stack)
1770 goto out;
1771 callchain_ret = 1;
1772 }
1773 }
1774
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001775 trace__printf_interrupted_entry(trace, sample);
1776 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001777
1778 if (trace->trace_syscalls)
1779 fprintf(trace->output, "( ): ");
1780
1781 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001782
Wang Nan1d6c9402016-02-26 09:31:55 +00001783 if (perf_evsel__is_bpf_output(evsel)) {
1784 bpf_output__fprintf(trace, sample);
1785 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001786 event_format__fprintf(evsel->tp_format, sample->cpu,
1787 sample->raw_data, sample->raw_size,
1788 trace->output);
1789 }
1790
1791 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001792
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001793 if (callchain_ret > 0)
1794 trace__fprintf_callchain(trace, sample);
1795 else if (callchain_ret < 0)
1796 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1797out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001798 return 0;
1799}
1800
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001801static void print_location(FILE *f, struct perf_sample *sample,
1802 struct addr_location *al,
1803 bool print_dso, bool print_sym)
1804{
1805
1806 if ((verbose || print_dso) && al->map)
1807 fprintf(f, "%s@", al->map->dso->long_name);
1808
1809 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001810 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001811 al->addr - al->sym->start);
1812 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001813 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001814 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001815 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001816}
1817
1818static int trace__pgfault(struct trace *trace,
1819 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001820 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001821 struct perf_sample *sample)
1822{
1823 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001824 struct addr_location al;
1825 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001826 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001827 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001828 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001829
1830 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001831
1832 if (sample->callchain) {
1833 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1834 if (callchain_ret == 0) {
1835 if (callchain_cursor.nr < trace->min_stack)
1836 goto out_put;
1837 callchain_ret = 1;
1838 }
1839 }
1840
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001841 ttrace = thread__trace(thread, trace->output);
1842 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001843 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001844
1845 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1846 ttrace->pfmaj++;
1847 else
1848 ttrace->pfmin++;
1849
1850 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001851 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001852
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001853 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001854 sample->ip, &al);
1855
1856 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1857
1858 fprintf(trace->output, "%sfault [",
1859 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1860 "maj" : "min");
1861
1862 print_location(trace->output, sample, &al, false, true);
1863
1864 fprintf(trace->output, "] => ");
1865
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001866 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001867 sample->addr, &al);
1868
1869 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001870 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001871 MAP__FUNCTION, sample->addr, &al);
1872
1873 if (al.map)
1874 map_type = 'x';
1875 else
1876 map_type = '?';
1877 }
1878
1879 print_location(trace->output, sample, &al, true, false);
1880
1881 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001882
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001883 if (callchain_ret > 0)
1884 trace__fprintf_callchain(trace, sample);
1885 else if (callchain_ret < 0)
1886 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001887out:
1888 err = 0;
1889out_put:
1890 thread__put(thread);
1891 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001892}
1893
David Ahernbdc89662013-08-28 22:29:53 -06001894static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1895{
1896 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1897 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1898 return false;
1899
1900 if (trace->pid_list || trace->tid_list)
1901 return true;
1902
1903 return false;
1904}
1905
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001906static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001907 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001908 struct perf_sample *sample)
1909{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001910 /*
1911 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1912 * and don't use sample->time unconditionally, we may end up having
1913 * some other event in the future without PERF_SAMPLE_TIME for good
1914 * reason, i.e. we may not be interested in its timestamps, just in
1915 * it taking place, picking some piece of information when it
1916 * appears in our event stream (vfs_getname comes to mind).
1917 */
1918 if (trace->base_time == 0 && !trace->full_time &&
1919 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001920 trace->base_time = sample->time;
1921}
1922
David Ahern6810fc92013-08-28 22:29:52 -06001923static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001924 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001925 struct perf_sample *sample,
1926 struct perf_evsel *evsel,
1927 struct machine *machine __maybe_unused)
1928{
1929 struct trace *trace = container_of(tool, struct trace, tool);
1930 int err = 0;
1931
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001932 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001933
David Ahernbdc89662013-08-28 22:29:53 -06001934 if (skip_sample(trace, sample))
1935 return 0;
1936
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001937 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001938
David Ahern31605652013-12-04 19:41:41 -07001939 if (handler) {
1940 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001941 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001942 }
David Ahern6810fc92013-08-28 22:29:52 -06001943
1944 return err;
1945}
1946
David Ahernbdc89662013-08-28 22:29:53 -06001947static int parse_target_str(struct trace *trace)
1948{
1949 if (trace->opts.target.pid) {
1950 trace->pid_list = intlist__new(trace->opts.target.pid);
1951 if (trace->pid_list == NULL) {
1952 pr_err("Error parsing process id string\n");
1953 return -EINVAL;
1954 }
1955 }
1956
1957 if (trace->opts.target.tid) {
1958 trace->tid_list = intlist__new(trace->opts.target.tid);
1959 if (trace->tid_list == NULL) {
1960 pr_err("Error parsing thread id string\n");
1961 return -EINVAL;
1962 }
1963 }
1964
1965 return 0;
1966}
1967
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001968static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001969{
1970 unsigned int rec_argc, i, j;
1971 const char **rec_argv;
1972 const char * const record_args[] = {
1973 "record",
1974 "-R",
1975 "-m", "1024",
1976 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001977 };
1978
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001979 const char * const sc_args[] = { "-e", };
1980 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1981 const char * const majpf_args[] = { "-e", "major-faults" };
1982 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1983 const char * const minpf_args[] = { "-e", "minor-faults" };
1984 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1985
David Ahern9aca7f12013-12-04 19:41:39 -07001986 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001987 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1988 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001989 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1990
1991 if (rec_argv == NULL)
1992 return -ENOMEM;
1993
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001994 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001995 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001996 rec_argv[j++] = record_args[i];
1997
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001998 if (trace->trace_syscalls) {
1999 for (i = 0; i < sc_args_nr; i++)
2000 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002001
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002002 /* event string may be different for older kernels - e.g., RHEL6 */
2003 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2004 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2005 else if (is_valid_tracepoint("syscalls:sys_enter"))
2006 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2007 else {
2008 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2009 return -1;
2010 }
David Ahern9aca7f12013-12-04 19:41:39 -07002011 }
David Ahern9aca7f12013-12-04 19:41:39 -07002012
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002013 if (trace->trace_pgfaults & TRACE_PFMAJ)
2014 for (i = 0; i < majpf_args_nr; i++)
2015 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002016
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002017 if (trace->trace_pgfaults & TRACE_PFMIN)
2018 for (i = 0; i < minpf_args_nr; i++)
2019 rec_argv[j++] = minpf_args[i];
2020
2021 for (i = 0; i < (unsigned int)argc; i++)
2022 rec_argv[j++] = argv[i];
2023
2024 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002025}
2026
David Ahernbf2575c2013-10-08 21:26:53 -06002027static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2028
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002029static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002030{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002031 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002032
2033 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002034 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002035
2036 if (perf_evsel__field(evsel, "pathname") == NULL) {
2037 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002038 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002039 }
2040
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002041 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002042 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002043 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002044}
2045
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002046static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002047{
2048 struct perf_evsel *evsel;
2049 struct perf_event_attr attr = {
2050 .type = PERF_TYPE_SOFTWARE,
2051 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002052 };
2053
2054 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002055 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002056
2057 event_attr_init(&attr);
2058
2059 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002060 if (evsel)
2061 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002062
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002063 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002064}
2065
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002066static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2067{
2068 const u32 type = event->header.type;
2069 struct perf_evsel *evsel;
2070
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002071 if (type != PERF_RECORD_SAMPLE) {
2072 trace__process_event(trace, trace->host, event, sample);
2073 return;
2074 }
2075
2076 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2077 if (evsel == NULL) {
2078 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2079 return;
2080 }
2081
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002082 trace__set_base_time(trace, evsel, sample);
2083
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002084 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2085 sample->raw_data == NULL) {
2086 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2087 perf_evsel__name(evsel), sample->tid,
2088 sample->cpu, sample->raw_size);
2089 } else {
2090 tracepoint_handler handler = evsel->handler;
2091 handler(trace, evsel, event, sample);
2092 }
2093}
2094
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002095static int trace__add_syscall_newtp(struct trace *trace)
2096{
2097 int ret = -1;
2098 struct perf_evlist *evlist = trace->evlist;
2099 struct perf_evsel *sys_enter, *sys_exit;
2100
2101 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2102 if (sys_enter == NULL)
2103 goto out;
2104
2105 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2106 goto out_delete_sys_enter;
2107
2108 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2109 if (sys_exit == NULL)
2110 goto out_delete_sys_enter;
2111
2112 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2113 goto out_delete_sys_exit;
2114
2115 perf_evlist__add(evlist, sys_enter);
2116 perf_evlist__add(evlist, sys_exit);
2117
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002118 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002119 /*
2120 * We're interested only in the user space callchain
2121 * leading to the syscall, allow overriding that for
2122 * debugging reasons using --kernel_syscall_callchains
2123 */
2124 sys_exit->attr.exclude_callchain_kernel = 1;
2125 }
2126
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002127 trace->syscalls.events.sys_enter = sys_enter;
2128 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002129
2130 ret = 0;
2131out:
2132 return ret;
2133
2134out_delete_sys_exit:
2135 perf_evsel__delete_priv(sys_exit);
2136out_delete_sys_enter:
2137 perf_evsel__delete_priv(sys_enter);
2138 goto out;
2139}
2140
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002141static int trace__set_ev_qualifier_filter(struct trace *trace)
2142{
2143 int err = -1;
2144 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2145 trace->ev_qualifier_ids.nr,
2146 trace->ev_qualifier_ids.entries);
2147
2148 if (filter == NULL)
2149 goto out_enomem;
2150
2151 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2152 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2153
2154 free(filter);
2155out:
2156 return err;
2157out_enomem:
2158 errno = ENOMEM;
2159 goto out;
2160}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002161
Namhyung Kimf15eb532012-10-05 14:02:16 +09002162static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002163{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002164 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002165 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002166 int err = -1, i;
2167 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002168 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002169 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002170
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002171 trace->live = true;
2172
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002173 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002174 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002175
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002176 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002177 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002178
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002179 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2180 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2181 if (pgfault_maj == NULL)
2182 goto out_error_mem;
2183 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002184 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002185
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002186 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2187 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2188 if (pgfault_min == NULL)
2189 goto out_error_mem;
2190 perf_evlist__add(evlist, pgfault_min);
2191 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002192
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002193 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002194 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2195 trace__sched_stat_runtime))
2196 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002197
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002198 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2199 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002200 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002201 goto out_delete_evlist;
2202 }
2203
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002204 err = trace__symbols_init(trace, evlist);
2205 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002206 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002207 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002208 }
2209
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002210 perf_evlist__config(evlist, &trace->opts, NULL);
2211
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002212 if (callchain_param.enabled) {
2213 bool use_identifier = false;
2214
2215 if (trace->syscalls.events.sys_exit) {
2216 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2217 &trace->opts, &callchain_param);
2218 use_identifier = true;
2219 }
2220
2221 if (pgfault_maj) {
2222 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2223 use_identifier = true;
2224 }
2225
2226 if (pgfault_min) {
2227 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2228 use_identifier = true;
2229 }
2230
2231 if (use_identifier) {
2232 /*
2233 * Now we have evsels with different sample_ids, use
2234 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2235 * from a fixed position in each ring buffer record.
2236 *
2237 * As of this the changeset introducing this comment, this
2238 * isn't strictly needed, as the fields that can come before
2239 * PERF_SAMPLE_ID are all used, but we'll probably disable
2240 * some of those for things like copying the payload of
2241 * pointer syscall arguments, and for vfs_getname we don't
2242 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2243 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2244 */
2245 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2246 perf_evlist__reset_sample_bit(evlist, ID);
2247 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002248 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002249
Namhyung Kimf15eb532012-10-05 14:02:16 +09002250 signal(SIGCHLD, sig_handler);
2251 signal(SIGINT, sig_handler);
2252
2253 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002254 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002255 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002256 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002257 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002258 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002259 }
2260 }
2261
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002262 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002263 if (err < 0)
2264 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002265
Wang Nanba504232016-02-26 09:31:54 +00002266 err = bpf__apply_obj_config();
2267 if (err) {
2268 char errbuf[BUFSIZ];
2269
2270 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2271 pr_err("ERROR: Apply config to BPF failed: %s\n",
2272 errbuf);
2273 goto out_error_open;
2274 }
2275
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002276 /*
2277 * Better not use !target__has_task() here because we need to cover the
2278 * case where no threads were specified in the command line, but a
2279 * workload was, and in that case we will fill in the thread_map when
2280 * we fork the workload in perf_evlist__prepare_workload.
2281 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002282 if (trace->filter_pids.nr > 0)
2283 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002284 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002285 err = perf_evlist__set_filter_pid(evlist, getpid());
2286
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002287 if (err < 0)
2288 goto out_error_mem;
2289
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002290 if (trace->ev_qualifier_ids.nr > 0) {
2291 err = trace__set_ev_qualifier_filter(trace);
2292 if (err < 0)
2293 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002294
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002295 pr_debug("event qualifier tracepoint filter: %s\n",
2296 trace->syscalls.events.sys_exit->filter);
2297 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002298
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002299 err = perf_evlist__apply_filters(evlist, &evsel);
2300 if (err < 0)
2301 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002302
Jiri Olsaf8850372013-11-28 17:57:22 +01002303 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002304 if (err < 0)
2305 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002306
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002307 if (!target__none(&trace->opts.target))
2308 perf_evlist__enable(evlist);
2309
Namhyung Kimf15eb532012-10-05 14:02:16 +09002310 if (forks)
2311 perf_evlist__start_workload(evlist);
2312
Jiri Olsae13798c2015-06-23 00:36:02 +02002313 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002314 evlist->threads->nr > 1 ||
2315 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002316again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002317 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002318
2319 for (i = 0; i < evlist->nr_mmaps; i++) {
2320 union perf_event *event;
2321
2322 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002323 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002324
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002325 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002326
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002327 err = perf_evlist__parse_sample(evlist, event, &sample);
2328 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002329 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002330 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002331 }
2332
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002333 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002334next_event:
2335 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002336
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002337 if (interrupted)
2338 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002339
2340 if (done && !draining) {
2341 perf_evlist__disable(evlist);
2342 draining = true;
2343 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002344 }
2345 }
2346
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002347 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002348 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002349
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002350 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2351 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2352 draining = true;
2353
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002354 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002355 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002356 } else {
2357 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002358 }
2359
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002360out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002361 thread__zput(trace->current);
2362
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002363 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002364
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002365 if (!err) {
2366 if (trace->summary)
2367 trace__fprintf_thread_summary(trace, trace->output);
2368
2369 if (trace->show_tool_stats) {
2370 fprintf(trace->output, "Stats:\n "
2371 " vfs_getname : %" PRIu64 "\n"
2372 " proc_getname: %" PRIu64 "\n",
2373 trace->stats.vfs_getname,
2374 trace->stats.proc_getname);
2375 }
2376 }
David Ahernbf2575c2013-10-08 21:26:53 -06002377
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002378out_delete_evlist:
2379 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002380 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002381 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002382 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002383{
2384 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002385
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002386out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002387 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002388 goto out_error;
2389
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002390out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002391 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002392 goto out_error;
2393
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002394out_error_mmap:
2395 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2396 goto out_error;
2397
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002398out_error_open:
2399 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2400
2401out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002402 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302403 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002404
2405out_error_apply_filters:
2406 fprintf(trace->output,
2407 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2408 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002409 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002410 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002411}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002412out_error_mem:
2413 fprintf(trace->output, "Not enough memory to run!\n");
2414 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002415
2416out_errno:
2417 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2418 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002419}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002420
David Ahern6810fc92013-08-28 22:29:52 -06002421static int trace__replay(struct trace *trace)
2422{
2423 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002424 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002425 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002426 struct perf_data_file file = {
2427 .path = input_name,
2428 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002429 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002430 };
David Ahern6810fc92013-08-28 22:29:52 -06002431 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002432 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002433 int err = -1;
2434
2435 trace->tool.sample = trace__process_sample;
2436 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002437 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002438 trace->tool.comm = perf_event__process_comm;
2439 trace->tool.exit = perf_event__process_exit;
2440 trace->tool.fork = perf_event__process_fork;
2441 trace->tool.attr = perf_event__process_attr;
2442 trace->tool.tracing_data = perf_event__process_tracing_data;
2443 trace->tool.build_id = perf_event__process_build_id;
2444
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002445 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002446 trace->tool.ordering_requires_timestamps = true;
2447
2448 /* add tid to output */
2449 trace->multiple_threads = true;
2450
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002451 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002452 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002453 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002454
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002455 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002456 goto out;
2457
David Ahern8fb598e2013-09-28 13:13:00 -06002458 trace->host = &session->machines.host;
2459
David Ahern6810fc92013-08-28 22:29:52 -06002460 err = perf_session__set_tracepoints_handlers(session, handlers);
2461 if (err)
2462 goto out;
2463
Namhyung Kim003824e2013-11-12 15:25:00 +09002464 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2465 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002466 /* older kernels have syscalls tp versus raw_syscalls */
2467 if (evsel == NULL)
2468 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2469 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002470
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002471 if (evsel &&
2472 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2473 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002474 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2475 goto out;
2476 }
2477
2478 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2479 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002480 if (evsel == NULL)
2481 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2482 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002483 if (evsel &&
2484 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2485 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002486 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002487 goto out;
2488 }
2489
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002490 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002491 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2492 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2493 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2494 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2495 evsel->handler = trace__pgfault;
2496 }
2497
David Ahernbdc89662013-08-28 22:29:53 -06002498 err = parse_target_str(trace);
2499 if (err != 0)
2500 goto out;
2501
David Ahern6810fc92013-08-28 22:29:52 -06002502 setup_pager();
2503
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002504 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002505 if (err)
2506 pr_err("Failed to process events, error %d", err);
2507
David Ahernbf2575c2013-10-08 21:26:53 -06002508 else if (trace->summary)
2509 trace__fprintf_thread_summary(trace, trace->output);
2510
David Ahern6810fc92013-08-28 22:29:52 -06002511out:
2512 perf_session__delete(session);
2513
2514 return err;
2515}
2516
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002517static size_t trace__fprintf_threads_header(FILE *fp)
2518{
2519 size_t printed;
2520
Pekka Enberg99ff7152013-11-12 16:42:14 +02002521 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002522
2523 return printed;
2524}
2525
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002526DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2527 struct stats *stats;
2528 double msecs;
2529 int syscall;
2530)
2531{
2532 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2533 struct stats *stats = source->priv;
2534
2535 entry->syscall = source->i;
2536 entry->stats = stats;
2537 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2538}
2539
David Ahernbf2575c2013-10-08 21:26:53 -06002540static size_t thread__dump_stats(struct thread_trace *ttrace,
2541 struct trace *trace, FILE *fp)
2542{
David Ahernbf2575c2013-10-08 21:26:53 -06002543 size_t printed = 0;
2544 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002545 struct rb_node *nd;
2546 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002547
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002548 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002549 return 0;
2550
2551 printed += fprintf(fp, "\n");
2552
Milian Wolff834fd462015-08-06 11:24:29 +02002553 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2554 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2555 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002556
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002557 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002558 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002559 if (stats) {
2560 double min = (double)(stats->min) / NSEC_PER_MSEC;
2561 double max = (double)(stats->max) / NSEC_PER_MSEC;
2562 double avg = avg_stats(stats);
2563 double pct;
2564 u64 n = (u64) stats->n;
2565
2566 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2567 avg /= NSEC_PER_MSEC;
2568
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002569 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002570 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002571 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002572 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002573 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002574 }
David Ahernbf2575c2013-10-08 21:26:53 -06002575 }
2576
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002577 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002578 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002579
2580 return printed;
2581}
2582
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002583static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002584{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002585 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002586 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002587 double ratio;
2588
2589 if (ttrace == NULL)
2590 return 0;
2591
2592 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2593
Pekka Enberg15e65c62013-11-14 18:43:30 +02002594 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002595 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002596 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002597 if (ttrace->pfmaj)
2598 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2599 if (ttrace->pfmin)
2600 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002601 if (trace->sched)
2602 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2603 else if (fputc('\n', fp) != EOF)
2604 ++printed;
2605
David Ahernbf2575c2013-10-08 21:26:53 -06002606 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002607
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002608 return printed;
2609}
David Ahern896cbb52013-09-28 13:12:59 -06002610
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002611static unsigned long thread__nr_events(struct thread_trace *ttrace)
2612{
2613 return ttrace ? ttrace->nr_events : 0;
2614}
2615
2616DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2617 struct thread *thread;
2618)
2619{
2620 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002621}
2622
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002623static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2624{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002625 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2626 size_t printed = trace__fprintf_threads_header(fp);
2627 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002628
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002629 if (threads == NULL) {
2630 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2631 return 0;
2632 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002633
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002634 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002635 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2636
2637 resort_rb__delete(threads);
2638
2639 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002640}
2641
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002642static int trace__set_duration(const struct option *opt, const char *str,
2643 int unset __maybe_unused)
2644{
2645 struct trace *trace = opt->value;
2646
2647 trace->duration_filter = atof(str);
2648 return 0;
2649}
2650
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002651static int trace__set_filter_pids(const struct option *opt, const char *str,
2652 int unset __maybe_unused)
2653{
2654 int ret = -1;
2655 size_t i;
2656 struct trace *trace = opt->value;
2657 /*
2658 * FIXME: introduce a intarray class, plain parse csv and create a
2659 * { int nr, int entries[] } struct...
2660 */
2661 struct intlist *list = intlist__new(str);
2662
2663 if (list == NULL)
2664 return -1;
2665
2666 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2667 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2668
2669 if (trace->filter_pids.entries == NULL)
2670 goto out;
2671
2672 trace->filter_pids.entries[0] = getpid();
2673
2674 for (i = 1; i < trace->filter_pids.nr; ++i)
2675 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2676
2677 intlist__delete(list);
2678 ret = 0;
2679out:
2680 return ret;
2681}
2682
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002683static int trace__open_output(struct trace *trace, const char *filename)
2684{
2685 struct stat st;
2686
2687 if (!stat(filename, &st) && st.st_size) {
2688 char oldname[PATH_MAX];
2689
2690 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2691 unlink(oldname);
2692 rename(filename, oldname);
2693 }
2694
2695 trace->output = fopen(filename, "w");
2696
2697 return trace->output == NULL ? -errno : 0;
2698}
2699
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002700static int parse_pagefaults(const struct option *opt, const char *str,
2701 int unset __maybe_unused)
2702{
2703 int *trace_pgfaults = opt->value;
2704
2705 if (strcmp(str, "all") == 0)
2706 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2707 else if (strcmp(str, "maj") == 0)
2708 *trace_pgfaults |= TRACE_PFMAJ;
2709 else if (strcmp(str, "min") == 0)
2710 *trace_pgfaults |= TRACE_PFMIN;
2711 else
2712 return -1;
2713
2714 return 0;
2715}
2716
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002717static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2718{
2719 struct perf_evsel *evsel;
2720
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002721 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002722 evsel->handler = handler;
2723}
2724
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002725int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2726{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002727 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002728 "perf trace [<options>] [<command>]",
2729 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002730 "perf trace record [<options>] [<command>]",
2731 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002732 NULL
2733 };
2734 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002735 .syscalls = {
2736 . max = -1,
2737 },
2738 .opts = {
2739 .target = {
2740 .uid = UINT_MAX,
2741 .uses_mmap = true,
2742 },
2743 .user_freq = UINT_MAX,
2744 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002745 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002746 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002747 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002748 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002749 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002750 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002751 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002752 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002753 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002754 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002755 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002756 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002757 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002758 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2759 "event selector. use 'perf list' to list available events",
2760 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002761 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2762 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002763 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002764 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002765 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002766 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002767 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2768 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002769 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002770 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002771 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2772 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002773 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002774 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002775 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002776 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002777 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002778 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002779 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2780 "number of mmap data pages",
2781 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002782 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002783 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002784 OPT_CALLBACK(0, "duration", &trace, "float",
2785 "show only events with duration > N.M ms",
2786 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002787 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002788 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002789 OPT_BOOLEAN('T', "time", &trace.full_time,
2790 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002791 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2792 "Show only syscall summary with statistics"),
2793 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2794 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002795 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2796 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002797 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002798 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002799 OPT_CALLBACK(0, "call-graph", &trace.opts,
2800 "record_mode[,record_size]", record_callchain_help,
2801 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002802 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2803 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002804 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2805 "Set the minimum stack depth when parsing the callchain, "
2806 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002807 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2808 "Set the maximum stack depth when parsing the callchain, "
2809 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002810 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002811 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2812 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002813 OPT_END()
2814 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002815 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002816 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002817 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002818 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002819 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002820
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002821 signal(SIGSEGV, sighandler_dump_stack);
2822 signal(SIGFPE, sighandler_dump_stack);
2823
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002824 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002825 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002826
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002827 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002828 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002829 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002830 goto out;
2831 }
2832
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002833 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2834 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002835
Wang Nand7888572016-04-08 15:07:24 +00002836 err = bpf__setup_stdout(trace.evlist);
2837 if (err) {
2838 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2839 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2840 goto out;
2841 }
2842
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002843 err = -1;
2844
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002845 if (trace.trace_pgfaults) {
2846 trace.opts.sample_address = true;
2847 trace.opts.sample_time = true;
2848 }
2849
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002850 if (trace.opts.mmap_pages == UINT_MAX)
2851 mmap_pages_user_set = false;
2852
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002853 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002854 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002855 max_stack_user_set = false;
2856 }
2857
2858#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002859 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002860 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2861#endif
2862
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002863 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002864 if (!mmap_pages_user_set && geteuid() == 0)
2865 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2866
Milian Wolff566a0882016-04-08 13:34:15 +02002867 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002868 }
Milian Wolff566a0882016-04-08 13:34:15 +02002869
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002870 if (trace.evlist->nr_entries > 0)
2871 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2872
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002873 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2874 return trace__record(&trace, argc-1, &argv[1]);
2875
2876 /* summary_only implies summary option, but don't overwrite summary if set */
2877 if (trace.summary_only)
2878 trace.summary = trace.summary_only;
2879
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002880 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2881 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002882 pr_err("Please specify something to trace.\n");
2883 return -1;
2884 }
2885
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002886 if (!trace.trace_syscalls && ev_qualifier_str) {
2887 pr_err("The -e option can't be used with --no-syscalls.\n");
2888 goto out;
2889 }
2890
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002891 if (output_name != NULL) {
2892 err = trace__open_output(&trace, output_name);
2893 if (err < 0) {
2894 perror("failed to create output file");
2895 goto out;
2896 }
2897 }
2898
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002899 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2900
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002901 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002902 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002903 struct strlist_config slist_config = {
2904 .dirname = system_path(STRACE_GROUPS_DIR),
2905 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002906
2907 trace.not_ev_qualifier = *s == '!';
2908 if (trace.not_ev_qualifier)
2909 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002910 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002911 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002912 fputs("Not enough memory to parse event qualifier",
2913 trace.output);
2914 err = -ENOMEM;
2915 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002916 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002917
2918 err = trace__validate_ev_qualifier(&trace);
2919 if (err)
2920 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002921 }
2922
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002923 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002924 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002925 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002926 fprintf(trace.output, "%s", bf);
2927 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002928 }
2929
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002930 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002931 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002932 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002933 fprintf(trace.output, "%s", bf);
2934 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002935 }
2936
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002937 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002938 trace.opts.target.system_wide = true;
2939
David Ahern6810fc92013-08-28 22:29:52 -06002940 if (input_name)
2941 err = trace__replay(&trace);
2942 else
2943 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002944
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002945out_close:
2946 if (output_name != NULL)
2947 fclose(trace.output);
2948out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002949 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002950}