blob: e04ba9d852d4ac94c8d4c9c3bc9f920348c4e9c1 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/filter.h>
45#include <linux/audit.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030046#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030047#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030048#include <linux/time64.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 Melof0bbd602016-09-28 13:45:38 -0300745 { .name = "sched_getattr", .errmsg = true, },
746 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300747 { .name = "sched_setscheduler", .errmsg = true,
748 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300749 { .name = "seccomp", .errmsg = true,
750 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
751 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300752 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300753 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300754 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300755 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300756 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300757 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300758 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300759 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300760 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300761 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300762 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300763 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300764 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300765 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300766 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
767 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300768 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300769 { .name = "socketpair", .errmsg = true,
770 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
771 [1] = SCA_SK_TYPE, /* type */ },
772 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300773 { .name = "stat", .errmsg = true, .alias = "newstat", },
774 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300775 { .name = "swapoff", .errmsg = true,
776 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
777 { .name = "swapon", .errmsg = true,
778 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300779 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300780 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300781 { .name = "tgkill", .errmsg = true,
782 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
783 { .name = "tkill", .errmsg = true,
784 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300785 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300786 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300787 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300788 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
789 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300790 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300791 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
792 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300793 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300794 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300795 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300796 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300797 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300798 { .name = "write", .errmsg = true, },
799 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300800};
801
802static int syscall_fmt__cmp(const void *name, const void *fmtp)
803{
804 const struct syscall_fmt *fmt = fmtp;
805 return strcmp(name, fmt->name);
806}
807
808static struct syscall_fmt *syscall_fmt__find(const char *name)
809{
810 const int nmemb = ARRAY_SIZE(syscall_fmts);
811 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
812}
813
814struct syscall {
815 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300816 int nr_args;
817 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300818 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300819 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300820 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300821 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300822 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300823};
824
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200825static size_t fprintf_duration(unsigned long t, FILE *fp)
826{
827 double duration = (double)t / NSEC_PER_MSEC;
828 size_t printed = fprintf(fp, "(");
829
830 if (duration >= 1.0)
831 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
832 else if (duration >= 0.01)
833 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
834 else
835 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300836 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200837}
838
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300839/**
840 * filename.ptr: The filename char pointer that will be vfs_getname'd
841 * filename.entry_str_pos: Where to insert the string translated from
842 * filename.ptr by the vfs_getname tracepoint/kprobe.
843 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300844struct thread_trace {
845 u64 entry_time;
846 u64 exit_time;
847 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300848 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400849 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300850 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300851 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300852 struct {
853 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300854 short int entry_str_pos;
855 bool pending_open;
856 unsigned int namelen;
857 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300858 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300859 struct {
860 int max;
861 char **table;
862 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600863
864 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300865};
866
867static struct thread_trace *thread_trace__new(void)
868{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300869 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
870
871 if (ttrace)
872 ttrace->paths.max = -1;
873
David Ahernbf2575c2013-10-08 21:26:53 -0600874 ttrace->syscall_stats = intlist__new(NULL);
875
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300876 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300877}
878
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300879static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300880{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300881 struct thread_trace *ttrace;
882
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300883 if (thread == NULL)
884 goto fail;
885
Namhyung Kim89dceb22014-10-06 09:46:03 +0900886 if (thread__priv(thread) == NULL)
887 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300888
Namhyung Kim89dceb22014-10-06 09:46:03 +0900889 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890 goto fail;
891
Namhyung Kim89dceb22014-10-06 09:46:03 +0900892 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300893 ++ttrace->nr_events;
894
895 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300896fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300897 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300898 "WARNING: not enough memory, dropping samples!\n");
899 return NULL;
900}
901
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400902#define TRACE_PFMAJ (1 << 0)
903#define TRACE_PFMIN (1 << 1)
904
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300905static const size_t trace__entry_str_size = 2048;
906
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300907static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900909 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300910
911 if (fd > ttrace->paths.max) {
912 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
913
914 if (npath == NULL)
915 return -1;
916
917 if (ttrace->paths.max != -1) {
918 memset(npath + ttrace->paths.max + 1, 0,
919 (fd - ttrace->paths.max) * sizeof(char *));
920 } else {
921 memset(npath, 0, (fd + 1) * sizeof(char *));
922 }
923
924 ttrace->paths.table = npath;
925 ttrace->paths.max = fd;
926 }
927
928 ttrace->paths.table[fd] = strdup(pathname);
929
930 return ttrace->paths.table[fd] != NULL ? 0 : -1;
931}
932
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300933static int thread__read_fd_path(struct thread *thread, int fd)
934{
935 char linkname[PATH_MAX], pathname[PATH_MAX];
936 struct stat st;
937 int ret;
938
939 if (thread->pid_ == thread->tid) {
940 scnprintf(linkname, sizeof(linkname),
941 "/proc/%d/fd/%d", thread->pid_, fd);
942 } else {
943 scnprintf(linkname, sizeof(linkname),
944 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
945 }
946
947 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
948 return -1;
949
950 ret = readlink(linkname, pathname, sizeof(pathname));
951
952 if (ret < 0 || ret > st.st_size)
953 return -1;
954
955 pathname[ret] = '\0';
956 return trace__set_fd_pathname(thread, fd, pathname);
957}
958
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300959static const char *thread__fd_path(struct thread *thread, int fd,
960 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300961{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900962 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300963
964 if (ttrace == NULL)
965 return NULL;
966
967 if (fd < 0)
968 return NULL;
969
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300970 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300971 if (!trace->live)
972 return NULL;
973 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300974 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300975 return NULL;
976 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977
978 return ttrace->paths.table[fd];
979}
980
981static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
982 struct syscall_arg *arg)
983{
984 int fd = arg->val;
985 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300986 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300987
988 if (path)
989 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
990
991 return printed;
992}
993
994static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
995 struct syscall_arg *arg)
996{
997 int fd = arg->val;
998 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +0900999 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001000
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001001 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1002 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003
1004 return printed;
1005}
1006
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001007static void thread__set_filename_pos(struct thread *thread, const char *bf,
1008 unsigned long ptr)
1009{
1010 struct thread_trace *ttrace = thread__priv(thread);
1011
1012 ttrace->filename.ptr = ptr;
1013 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1014}
1015
1016static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1017 struct syscall_arg *arg)
1018{
1019 unsigned long ptr = arg->val;
1020
1021 if (!arg->trace->vfs_getname)
1022 return scnprintf(bf, size, "%#x", ptr);
1023
1024 thread__set_filename_pos(arg->thread, bf, ptr);
1025 return 0;
1026}
1027
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001028static bool trace__filter_duration(struct trace *trace, double t)
1029{
1030 return t < (trace->duration_filter * NSEC_PER_MSEC);
1031}
1032
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001033static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1034{
1035 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1036
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001037 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001038}
1039
Namhyung Kimf15eb532012-10-05 14:02:16 +09001040static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001041static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001042
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001043static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001044{
1045 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001046 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001047}
1048
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001049static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001050 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001051{
1052 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001053 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001054
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001055 if (trace->multiple_threads) {
1056 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001057 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001058 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001059 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001060
1061 return printed;
1062}
1063
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001064static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001065 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001066{
1067 int ret = 0;
1068
1069 switch (event->header.type) {
1070 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001071 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001072 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001073 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001074 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001075 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001076 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001077 break;
1078 }
1079
1080 return ret;
1081}
1082
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001083static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001085 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086 struct machine *machine)
1087{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001088 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001089 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001090}
1091
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001092static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1093{
1094 struct machine *machine = vmachine;
1095
1096 if (machine->kptr_restrict_warned)
1097 return NULL;
1098
1099 if (symbol_conf.kptr_restrict) {
1100 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1101 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1102 "Kernel samples will not be resolved.\n");
1103 machine->kptr_restrict_warned = true;
1104 return NULL;
1105 }
1106
1107 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1108}
1109
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1111{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001112 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113
1114 if (err)
1115 return err;
1116
David Ahern8fb598e2013-09-28 13:13:00 -06001117 trace->host = machine__new_host();
1118 if (trace->host == NULL)
1119 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001121 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001122 return -errno;
1123
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001124 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001125 evlist->threads, trace__tool_process, false,
1126 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127 if (err)
1128 symbol__exit();
1129
1130 return err;
1131}
1132
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001133static int syscall__set_arg_fmts(struct syscall *sc)
1134{
1135 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001136 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001137
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001138 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001139 if (sc->arg_scnprintf == NULL)
1140 return -1;
1141
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001142 if (sc->fmt)
1143 sc->arg_parm = sc->fmt->arg_parm;
1144
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001145 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001146 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1147 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001148 else if (strcmp(field->type, "const char *") == 0 &&
1149 (strcmp(field->name, "filename") == 0 ||
1150 strcmp(field->name, "path") == 0 ||
1151 strcmp(field->name, "pathname") == 0))
1152 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001153 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001154 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001155 else if (strcmp(field->type, "pid_t") == 0)
1156 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001157 else if (strcmp(field->type, "umode_t") == 0)
1158 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001159 else if ((strcmp(field->type, "int") == 0 ||
1160 strcmp(field->type, "unsigned int") == 0 ||
1161 strcmp(field->type, "long") == 0) &&
1162 (len = strlen(field->name)) >= 2 &&
1163 strcmp(field->name + len - 2, "fd") == 0) {
1164 /*
1165 * /sys/kernel/tracing/events/syscalls/sys_enter*
1166 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1167 * 65 int
1168 * 23 unsigned int
1169 * 7 unsigned long
1170 */
1171 sc->arg_scnprintf[idx] = SCA_FD;
1172 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001173 ++idx;
1174 }
1175
1176 return 0;
1177}
1178
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001179static int trace__read_syscall_info(struct trace *trace, int id)
1180{
1181 char tp_name[128];
1182 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001183 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001184
1185 if (name == NULL)
1186 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001187
1188 if (id > trace->syscalls.max) {
1189 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1190
1191 if (nsyscalls == NULL)
1192 return -1;
1193
1194 if (trace->syscalls.max != -1) {
1195 memset(nsyscalls + trace->syscalls.max + 1, 0,
1196 (id - trace->syscalls.max) * sizeof(*sc));
1197 } else {
1198 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1199 }
1200
1201 trace->syscalls.table = nsyscalls;
1202 trace->syscalls.max = id;
1203 }
1204
1205 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001206 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001207
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001208 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001209
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001210 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001211 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001212
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001213 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001214 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001215 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001216 }
1217
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001218 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001219 return -1;
1220
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001221 sc->args = sc->tp_format->format.fields;
1222 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001223 /*
1224 * We need to check and discard the first variable '__syscall_nr'
1225 * or 'nr' that mean the syscall number. It is needless here.
1226 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1227 */
1228 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001229 sc->args = sc->args->next;
1230 --sc->nr_args;
1231 }
1232
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001233 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1234
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001235 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001236}
1237
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001238static int trace__validate_ev_qualifier(struct trace *trace)
1239{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001240 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001241 struct str_node *pos;
1242
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001243 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1244 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1245 sizeof(trace->ev_qualifier_ids.entries[0]));
1246
1247 if (trace->ev_qualifier_ids.entries == NULL) {
1248 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1249 trace->output);
1250 err = -EINVAL;
1251 goto out;
1252 }
1253
1254 i = 0;
1255
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001256 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001257 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001258 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001259
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001260 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001261 if (err == 0) {
1262 fputs("Error:\tInvalid syscall ", trace->output);
1263 err = -EINVAL;
1264 } else {
1265 fputs(", ", trace->output);
1266 }
1267
1268 fputs(sc, trace->output);
1269 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001270
1271 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001272 }
1273
1274 if (err < 0) {
1275 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1276 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001277 zfree(&trace->ev_qualifier_ids.entries);
1278 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001279 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001280out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001281 return err;
1282}
1283
David Ahern55d43bc2015-02-19 15:00:22 -05001284/*
1285 * args is to be interpreted as a series of longs but we need to handle
1286 * 8-byte unaligned accesses. args points to raw_data within the event
1287 * and raw_data is guaranteed to be 8-byte unaligned because it is
1288 * preceded by raw_size which is a u32. So we need to copy args to a temp
1289 * variable to read it. Most notably this avoids extended load instructions
1290 * on unaligned addresses
1291 */
1292
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001293static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001294 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001295 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001296{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001297 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001298 unsigned char *p;
1299 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001300
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001301 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001302 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001303 u8 bit = 1;
1304 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001305 .idx = 0,
1306 .mask = 0,
1307 .trace = trace,
1308 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001309 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001310
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001311 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001312 field = field->next, ++arg.idx, bit <<= 1) {
1313 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001314 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001315
1316 /* special care for unaligned accesses */
1317 p = args + sizeof(unsigned long) * arg.idx;
1318 memcpy(&val, p, sizeof(val));
1319
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001320 /*
1321 * Suppress this argument if its value is zero and
1322 * and we don't have a string associated in an
1323 * strarray for it.
1324 */
David Ahern55d43bc2015-02-19 15:00:22 -05001325 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001326 !(sc->arg_scnprintf &&
1327 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1328 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001329 continue;
1330
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001331 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001332 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001333 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001334 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001335 if (sc->arg_parm)
1336 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001337 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1338 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001339 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001340 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001341 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001342 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001343 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001344 } else if (IS_ERR(sc->tp_format)) {
1345 /*
1346 * If we managed to read the tracepoint /format file, then we
1347 * may end up not having any args, like with gettid(), so only
1348 * print the raw args when we didn't manage to read it.
1349 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001350 int i = 0;
1351
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001352 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001353 /* special care for unaligned accesses */
1354 p = args + sizeof(unsigned long) * i;
1355 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001356 printed += scnprintf(bf + printed, size - printed,
1357 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001358 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001359 ++i;
1360 }
1361 }
1362
1363 return printed;
1364}
1365
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001366typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001367 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001368 struct perf_sample *sample);
1369
1370static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001371 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001372{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001373
1374 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001375
1376 /*
1377 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1378 * before that, leaving at a higher verbosity level till that is
1379 * explained. Reproduced with plain ftrace with:
1380 *
1381 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1382 * grep "NR -1 " /t/trace_pipe
1383 *
1384 * After generating some load on the machine.
1385 */
1386 if (verbose > 1) {
1387 static u64 n;
1388 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1389 id, perf_evsel__name(evsel), ++n);
1390 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001391 return NULL;
1392 }
1393
1394 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1395 trace__read_syscall_info(trace, id))
1396 goto out_cant_read;
1397
1398 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1399 goto out_cant_read;
1400
1401 return &trace->syscalls.table[id];
1402
1403out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001404 if (verbose) {
1405 fprintf(trace->output, "Problems reading syscall %d", id);
1406 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1407 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1408 fputs(" information\n", trace->output);
1409 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001410 return NULL;
1411}
1412
David Ahernbf2575c2013-10-08 21:26:53 -06001413static void thread__update_stats(struct thread_trace *ttrace,
1414 int id, struct perf_sample *sample)
1415{
1416 struct int_node *inode;
1417 struct stats *stats;
1418 u64 duration = 0;
1419
1420 inode = intlist__findnew(ttrace->syscall_stats, id);
1421 if (inode == NULL)
1422 return;
1423
1424 stats = inode->priv;
1425 if (stats == NULL) {
1426 stats = malloc(sizeof(struct stats));
1427 if (stats == NULL)
1428 return;
1429 init_stats(stats);
1430 inode->priv = stats;
1431 }
1432
1433 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1434 duration = sample->time - ttrace->entry_time;
1435
1436 update_stats(stats, duration);
1437}
1438
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001439static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1440{
1441 struct thread_trace *ttrace;
1442 u64 duration;
1443 size_t printed;
1444
1445 if (trace->current == NULL)
1446 return 0;
1447
1448 ttrace = thread__priv(trace->current);
1449
1450 if (!ttrace->entry_pending)
1451 return 0;
1452
1453 duration = sample->time - ttrace->entry_time;
1454
1455 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1456 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1457 ttrace->entry_pending = false;
1458
1459 return printed;
1460}
1461
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001462static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001463 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001464 struct perf_sample *sample)
1465{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001466 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001467 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001468 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001469 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001470 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001471 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001472 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001473
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001474 if (sc == NULL)
1475 return -1;
1476
David Ahern8fb598e2013-09-28 13:13:00 -06001477 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001478 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001479 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001480 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001481
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001482 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001483
1484 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001485 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001486 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001487 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001488 }
1489
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001490 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001491 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001492
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001493 ttrace->entry_time = sample->time;
1494 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001495 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001496
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001497 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001498 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001499
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001500 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001501 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001502 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001503 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001504 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001505 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001506 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001507 /* See trace__vfs_getname & trace__sys_exit */
1508 ttrace->filename.pending_open = false;
1509 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001510
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001511 if (trace->current != thread) {
1512 thread__put(trace->current);
1513 trace->current = thread__get(thread);
1514 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001515 err = 0;
1516out_put:
1517 thread__put(thread);
1518 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001519}
1520
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001521static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1522 struct perf_sample *sample,
1523 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001524{
1525 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001526
1527 if (machine__resolve(trace->host, &al, sample) < 0 ||
1528 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1529 return -1;
1530
1531 return 0;
1532}
1533
1534static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1535{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001536 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001537 const unsigned int print_opts = EVSEL__PRINT_SYM |
1538 EVSEL__PRINT_DSO |
1539 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001540
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001541 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001542}
1543
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001544static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001545 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001546 struct perf_sample *sample)
1547{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001548 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001549 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001550 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001551 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001552 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001553 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001554
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001555 if (sc == NULL)
1556 return -1;
1557
David Ahern8fb598e2013-09-28 13:13:00 -06001558 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001559 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001560 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001561 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001562
David Ahernbf2575c2013-10-08 21:26:53 -06001563 if (trace->summary)
1564 thread__update_stats(ttrace, id, sample);
1565
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001566 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001567
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001568 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001569 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1570 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001571 ++trace->stats.vfs_getname;
1572 }
1573
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001574 ttrace->exit_time = sample->time;
1575
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001576 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001577 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001578 if (trace__filter_duration(trace, duration))
1579 goto out;
1580 } else if (trace->duration_filter)
1581 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001582
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001583 if (sample->callchain) {
1584 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1585 if (callchain_ret == 0) {
1586 if (callchain_cursor.nr < trace->min_stack)
1587 goto out;
1588 callchain_ret = 1;
1589 }
1590 }
1591
David Ahernfd2eaba2013-11-12 09:31:15 -07001592 if (trace->summary_only)
1593 goto out;
1594
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001595 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001596
1597 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001598 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001599 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001600 fprintf(trace->output, " ... [");
1601 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1602 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001603 }
1604
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001605 if (sc->fmt == NULL) {
1606signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001607 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001608 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001609 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001610 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001611 *e = audit_errno_to_name(-ret);
1612
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001613 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001614 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001615 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001616 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001617 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001618 else if (sc->fmt->errpid) {
1619 struct thread *child = machine__find_thread(trace->host, ret, ret);
1620
1621 if (child != NULL) {
1622 fprintf(trace->output, ") = %ld", ret);
1623 if (child->comm_set)
1624 fprintf(trace->output, " (%s)", thread__comm_str(child));
1625 thread__put(child);
1626 }
1627 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001628 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001629
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001630 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001631
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001632 if (callchain_ret > 0)
1633 trace__fprintf_callchain(trace, sample);
1634 else if (callchain_ret < 0)
1635 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001636out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001637 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001638 err = 0;
1639out_put:
1640 thread__put(thread);
1641 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001642}
1643
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001644static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001645 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001646 struct perf_sample *sample)
1647{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001648 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1649 struct thread_trace *ttrace;
1650 size_t filename_len, entry_str_len, to_move;
1651 ssize_t remaining_space;
1652 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001653 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001654
1655 if (!thread)
1656 goto out;
1657
1658 ttrace = thread__priv(thread);
1659 if (!ttrace)
1660 goto out;
1661
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001662 filename_len = strlen(filename);
1663
1664 if (ttrace->filename.namelen < filename_len) {
1665 char *f = realloc(ttrace->filename.name, filename_len + 1);
1666
1667 if (f == NULL)
1668 goto out;
1669
1670 ttrace->filename.namelen = filename_len;
1671 ttrace->filename.name = f;
1672 }
1673
1674 strcpy(ttrace->filename.name, filename);
1675 ttrace->filename.pending_open = true;
1676
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001677 if (!ttrace->filename.ptr)
1678 goto out;
1679
1680 entry_str_len = strlen(ttrace->entry_str);
1681 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1682 if (remaining_space <= 0)
1683 goto out;
1684
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001685 if (filename_len > (size_t)remaining_space) {
1686 filename += filename_len - remaining_space;
1687 filename_len = remaining_space;
1688 }
1689
1690 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1691 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1692 memmove(pos + filename_len, pos, to_move);
1693 memcpy(pos, filename, filename_len);
1694
1695 ttrace->filename.ptr = 0;
1696 ttrace->filename.entry_str_pos = 0;
1697out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001698 return 0;
1699}
1700
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001701static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001702 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001703 struct perf_sample *sample)
1704{
1705 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1706 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001707 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001708 sample->pid,
1709 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001710 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001711
1712 if (ttrace == NULL)
1713 goto out_dump;
1714
1715 ttrace->runtime_ms += runtime_ms;
1716 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001717 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001718 return 0;
1719
1720out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001721 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001722 evsel->name,
1723 perf_evsel__strval(evsel, sample, "comm"),
1724 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1725 runtime,
1726 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001727 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001728 return 0;
1729}
1730
Wang Nan1d6c9402016-02-26 09:31:55 +00001731static void bpf_output__printer(enum binary_printer_ops op,
1732 unsigned int val, void *extra)
1733{
1734 FILE *output = extra;
1735 unsigned char ch = (unsigned char)val;
1736
1737 switch (op) {
1738 case BINARY_PRINT_CHAR_DATA:
1739 fprintf(output, "%c", isprint(ch) ? ch : '.');
1740 break;
1741 case BINARY_PRINT_DATA_BEGIN:
1742 case BINARY_PRINT_LINE_BEGIN:
1743 case BINARY_PRINT_ADDR:
1744 case BINARY_PRINT_NUM_DATA:
1745 case BINARY_PRINT_NUM_PAD:
1746 case BINARY_PRINT_SEP:
1747 case BINARY_PRINT_CHAR_PAD:
1748 case BINARY_PRINT_LINE_END:
1749 case BINARY_PRINT_DATA_END:
1750 default:
1751 break;
1752 }
1753}
1754
1755static void bpf_output__fprintf(struct trace *trace,
1756 struct perf_sample *sample)
1757{
1758 print_binary(sample->raw_data, sample->raw_size, 8,
1759 bpf_output__printer, trace->output);
1760}
1761
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001762static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1763 union perf_event *event __maybe_unused,
1764 struct perf_sample *sample)
1765{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001766 int callchain_ret = 0;
1767
1768 if (sample->callchain) {
1769 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1770 if (callchain_ret == 0) {
1771 if (callchain_cursor.nr < trace->min_stack)
1772 goto out;
1773 callchain_ret = 1;
1774 }
1775 }
1776
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001777 trace__printf_interrupted_entry(trace, sample);
1778 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001779
1780 if (trace->trace_syscalls)
1781 fprintf(trace->output, "( ): ");
1782
1783 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001784
Wang Nan1d6c9402016-02-26 09:31:55 +00001785 if (perf_evsel__is_bpf_output(evsel)) {
1786 bpf_output__fprintf(trace, sample);
1787 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001788 event_format__fprintf(evsel->tp_format, sample->cpu,
1789 sample->raw_data, sample->raw_size,
1790 trace->output);
1791 }
1792
1793 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001794
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001795 if (callchain_ret > 0)
1796 trace__fprintf_callchain(trace, sample);
1797 else if (callchain_ret < 0)
1798 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1799out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001800 return 0;
1801}
1802
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001803static void print_location(FILE *f, struct perf_sample *sample,
1804 struct addr_location *al,
1805 bool print_dso, bool print_sym)
1806{
1807
1808 if ((verbose || print_dso) && al->map)
1809 fprintf(f, "%s@", al->map->dso->long_name);
1810
1811 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001812 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001813 al->addr - al->sym->start);
1814 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001815 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001816 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001817 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001818}
1819
1820static int trace__pgfault(struct trace *trace,
1821 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001822 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001823 struct perf_sample *sample)
1824{
1825 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001826 struct addr_location al;
1827 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001828 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001829 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001830 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001831
1832 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001833
1834 if (sample->callchain) {
1835 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1836 if (callchain_ret == 0) {
1837 if (callchain_cursor.nr < trace->min_stack)
1838 goto out_put;
1839 callchain_ret = 1;
1840 }
1841 }
1842
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001843 ttrace = thread__trace(thread, trace->output);
1844 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001845 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001846
1847 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1848 ttrace->pfmaj++;
1849 else
1850 ttrace->pfmin++;
1851
1852 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001853 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001854
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001855 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001856 sample->ip, &al);
1857
1858 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1859
1860 fprintf(trace->output, "%sfault [",
1861 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1862 "maj" : "min");
1863
1864 print_location(trace->output, sample, &al, false, true);
1865
1866 fprintf(trace->output, "] => ");
1867
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001868 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001869 sample->addr, &al);
1870
1871 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001872 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001873 MAP__FUNCTION, sample->addr, &al);
1874
1875 if (al.map)
1876 map_type = 'x';
1877 else
1878 map_type = '?';
1879 }
1880
1881 print_location(trace->output, sample, &al, true, false);
1882
1883 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001884
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001885 if (callchain_ret > 0)
1886 trace__fprintf_callchain(trace, sample);
1887 else if (callchain_ret < 0)
1888 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001889out:
1890 err = 0;
1891out_put:
1892 thread__put(thread);
1893 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001894}
1895
David Ahernbdc89662013-08-28 22:29:53 -06001896static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1897{
1898 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1899 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1900 return false;
1901
1902 if (trace->pid_list || trace->tid_list)
1903 return true;
1904
1905 return false;
1906}
1907
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001908static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001909 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001910 struct perf_sample *sample)
1911{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001912 /*
1913 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1914 * and don't use sample->time unconditionally, we may end up having
1915 * some other event in the future without PERF_SAMPLE_TIME for good
1916 * reason, i.e. we may not be interested in its timestamps, just in
1917 * it taking place, picking some piece of information when it
1918 * appears in our event stream (vfs_getname comes to mind).
1919 */
1920 if (trace->base_time == 0 && !trace->full_time &&
1921 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001922 trace->base_time = sample->time;
1923}
1924
David Ahern6810fc92013-08-28 22:29:52 -06001925static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001926 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001927 struct perf_sample *sample,
1928 struct perf_evsel *evsel,
1929 struct machine *machine __maybe_unused)
1930{
1931 struct trace *trace = container_of(tool, struct trace, tool);
1932 int err = 0;
1933
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001934 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001935
David Ahernbdc89662013-08-28 22:29:53 -06001936 if (skip_sample(trace, sample))
1937 return 0;
1938
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001939 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001940
David Ahern31605652013-12-04 19:41:41 -07001941 if (handler) {
1942 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001943 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001944 }
David Ahern6810fc92013-08-28 22:29:52 -06001945
1946 return err;
1947}
1948
David Ahernbdc89662013-08-28 22:29:53 -06001949static int parse_target_str(struct trace *trace)
1950{
1951 if (trace->opts.target.pid) {
1952 trace->pid_list = intlist__new(trace->opts.target.pid);
1953 if (trace->pid_list == NULL) {
1954 pr_err("Error parsing process id string\n");
1955 return -EINVAL;
1956 }
1957 }
1958
1959 if (trace->opts.target.tid) {
1960 trace->tid_list = intlist__new(trace->opts.target.tid);
1961 if (trace->tid_list == NULL) {
1962 pr_err("Error parsing thread id string\n");
1963 return -EINVAL;
1964 }
1965 }
1966
1967 return 0;
1968}
1969
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001970static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001971{
1972 unsigned int rec_argc, i, j;
1973 const char **rec_argv;
1974 const char * const record_args[] = {
1975 "record",
1976 "-R",
1977 "-m", "1024",
1978 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001979 };
1980
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001981 const char * const sc_args[] = { "-e", };
1982 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1983 const char * const majpf_args[] = { "-e", "major-faults" };
1984 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1985 const char * const minpf_args[] = { "-e", "minor-faults" };
1986 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1987
David Ahern9aca7f12013-12-04 19:41:39 -07001988 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001989 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1990 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001991 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1992
1993 if (rec_argv == NULL)
1994 return -ENOMEM;
1995
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001996 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001997 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001998 rec_argv[j++] = record_args[i];
1999
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002000 if (trace->trace_syscalls) {
2001 for (i = 0; i < sc_args_nr; i++)
2002 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002003
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002004 /* event string may be different for older kernels - e.g., RHEL6 */
2005 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2006 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2007 else if (is_valid_tracepoint("syscalls:sys_enter"))
2008 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2009 else {
2010 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2011 return -1;
2012 }
David Ahern9aca7f12013-12-04 19:41:39 -07002013 }
David Ahern9aca7f12013-12-04 19:41:39 -07002014
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002015 if (trace->trace_pgfaults & TRACE_PFMAJ)
2016 for (i = 0; i < majpf_args_nr; i++)
2017 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002018
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002019 if (trace->trace_pgfaults & TRACE_PFMIN)
2020 for (i = 0; i < minpf_args_nr; i++)
2021 rec_argv[j++] = minpf_args[i];
2022
2023 for (i = 0; i < (unsigned int)argc; i++)
2024 rec_argv[j++] = argv[i];
2025
2026 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002027}
2028
David Ahernbf2575c2013-10-08 21:26:53 -06002029static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2030
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002031static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002032{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002033 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002034
2035 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002036 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002037
2038 if (perf_evsel__field(evsel, "pathname") == NULL) {
2039 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002040 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002041 }
2042
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002043 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002044 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002045 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002046}
2047
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002048static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002049{
2050 struct perf_evsel *evsel;
2051 struct perf_event_attr attr = {
2052 .type = PERF_TYPE_SOFTWARE,
2053 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002054 };
2055
2056 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002057 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002058
2059 event_attr_init(&attr);
2060
2061 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002062 if (evsel)
2063 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002064
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002065 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002066}
2067
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002068static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2069{
2070 const u32 type = event->header.type;
2071 struct perf_evsel *evsel;
2072
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002073 if (type != PERF_RECORD_SAMPLE) {
2074 trace__process_event(trace, trace->host, event, sample);
2075 return;
2076 }
2077
2078 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2079 if (evsel == NULL) {
2080 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2081 return;
2082 }
2083
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002084 trace__set_base_time(trace, evsel, sample);
2085
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002086 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2087 sample->raw_data == NULL) {
2088 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2089 perf_evsel__name(evsel), sample->tid,
2090 sample->cpu, sample->raw_size);
2091 } else {
2092 tracepoint_handler handler = evsel->handler;
2093 handler(trace, evsel, event, sample);
2094 }
2095}
2096
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002097static int trace__add_syscall_newtp(struct trace *trace)
2098{
2099 int ret = -1;
2100 struct perf_evlist *evlist = trace->evlist;
2101 struct perf_evsel *sys_enter, *sys_exit;
2102
2103 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2104 if (sys_enter == NULL)
2105 goto out;
2106
2107 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2108 goto out_delete_sys_enter;
2109
2110 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2111 if (sys_exit == NULL)
2112 goto out_delete_sys_enter;
2113
2114 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2115 goto out_delete_sys_exit;
2116
2117 perf_evlist__add(evlist, sys_enter);
2118 perf_evlist__add(evlist, sys_exit);
2119
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002120 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002121 /*
2122 * We're interested only in the user space callchain
2123 * leading to the syscall, allow overriding that for
2124 * debugging reasons using --kernel_syscall_callchains
2125 */
2126 sys_exit->attr.exclude_callchain_kernel = 1;
2127 }
2128
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002129 trace->syscalls.events.sys_enter = sys_enter;
2130 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002131
2132 ret = 0;
2133out:
2134 return ret;
2135
2136out_delete_sys_exit:
2137 perf_evsel__delete_priv(sys_exit);
2138out_delete_sys_enter:
2139 perf_evsel__delete_priv(sys_enter);
2140 goto out;
2141}
2142
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002143static int trace__set_ev_qualifier_filter(struct trace *trace)
2144{
2145 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002146 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002147 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2148 trace->ev_qualifier_ids.nr,
2149 trace->ev_qualifier_ids.entries);
2150
2151 if (filter == NULL)
2152 goto out_enomem;
2153
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002154 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter,
2155 "(%s) && (%s)", filter)) {
2156 sys_exit = trace->syscalls.events.sys_exit;
2157 err = perf_evsel__append_filter(sys_exit,
2158 "(%s) && (%s)", filter);
2159 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002160
2161 free(filter);
2162out:
2163 return err;
2164out_enomem:
2165 errno = ENOMEM;
2166 goto out;
2167}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002168
Namhyung Kimf15eb532012-10-05 14:02:16 +09002169static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002170{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002171 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002172 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002173 int err = -1, i;
2174 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002175 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002176 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002177
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002178 trace->live = true;
2179
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002180 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002181 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002182
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002183 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002184 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002185
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002186 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2187 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2188 if (pgfault_maj == NULL)
2189 goto out_error_mem;
2190 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002191 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002192
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002193 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2194 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2195 if (pgfault_min == NULL)
2196 goto out_error_mem;
2197 perf_evlist__add(evlist, pgfault_min);
2198 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002199
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002200 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002201 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2202 trace__sched_stat_runtime))
2203 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002204
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002205 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2206 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002207 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002208 goto out_delete_evlist;
2209 }
2210
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002211 err = trace__symbols_init(trace, evlist);
2212 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002213 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002214 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002215 }
2216
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002217 perf_evlist__config(evlist, &trace->opts, NULL);
2218
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002219 if (callchain_param.enabled) {
2220 bool use_identifier = false;
2221
2222 if (trace->syscalls.events.sys_exit) {
2223 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2224 &trace->opts, &callchain_param);
2225 use_identifier = true;
2226 }
2227
2228 if (pgfault_maj) {
2229 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2230 use_identifier = true;
2231 }
2232
2233 if (pgfault_min) {
2234 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2235 use_identifier = true;
2236 }
2237
2238 if (use_identifier) {
2239 /*
2240 * Now we have evsels with different sample_ids, use
2241 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2242 * from a fixed position in each ring buffer record.
2243 *
2244 * As of this the changeset introducing this comment, this
2245 * isn't strictly needed, as the fields that can come before
2246 * PERF_SAMPLE_ID are all used, but we'll probably disable
2247 * some of those for things like copying the payload of
2248 * pointer syscall arguments, and for vfs_getname we don't
2249 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2250 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2251 */
2252 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2253 perf_evlist__reset_sample_bit(evlist, ID);
2254 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002255 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002256
Namhyung Kimf15eb532012-10-05 14:02:16 +09002257 signal(SIGCHLD, sig_handler);
2258 signal(SIGINT, sig_handler);
2259
2260 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002261 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002262 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002263 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002264 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002265 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002266 }
2267 }
2268
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002269 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002270 if (err < 0)
2271 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002272
Wang Nanba504232016-02-26 09:31:54 +00002273 err = bpf__apply_obj_config();
2274 if (err) {
2275 char errbuf[BUFSIZ];
2276
2277 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2278 pr_err("ERROR: Apply config to BPF failed: %s\n",
2279 errbuf);
2280 goto out_error_open;
2281 }
2282
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002283 /*
2284 * Better not use !target__has_task() here because we need to cover the
2285 * case where no threads were specified in the command line, but a
2286 * workload was, and in that case we will fill in the thread_map when
2287 * we fork the workload in perf_evlist__prepare_workload.
2288 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002289 if (trace->filter_pids.nr > 0)
2290 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002291 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002292 err = perf_evlist__set_filter_pid(evlist, getpid());
2293
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002294 if (err < 0)
2295 goto out_error_mem;
2296
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002297 if (trace->ev_qualifier_ids.nr > 0) {
2298 err = trace__set_ev_qualifier_filter(trace);
2299 if (err < 0)
2300 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002301
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002302 pr_debug("event qualifier tracepoint filter: %s\n",
2303 trace->syscalls.events.sys_exit->filter);
2304 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002305
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002306 err = perf_evlist__apply_filters(evlist, &evsel);
2307 if (err < 0)
2308 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002309
Jiri Olsaf8850372013-11-28 17:57:22 +01002310 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002311 if (err < 0)
2312 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002313
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002314 if (!target__none(&trace->opts.target))
2315 perf_evlist__enable(evlist);
2316
Namhyung Kimf15eb532012-10-05 14:02:16 +09002317 if (forks)
2318 perf_evlist__start_workload(evlist);
2319
Jiri Olsae13798c2015-06-23 00:36:02 +02002320 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002321 evlist->threads->nr > 1 ||
2322 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002323again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002324 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002325
2326 for (i = 0; i < evlist->nr_mmaps; i++) {
2327 union perf_event *event;
2328
2329 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002330 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002331
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002332 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002334 err = perf_evlist__parse_sample(evlist, event, &sample);
2335 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002336 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002337 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002338 }
2339
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002340 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002341next_event:
2342 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002343
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002344 if (interrupted)
2345 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002346
2347 if (done && !draining) {
2348 perf_evlist__disable(evlist);
2349 draining = true;
2350 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002351 }
2352 }
2353
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002354 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002355 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002356
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002357 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2358 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2359 draining = true;
2360
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002361 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002362 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002363 } else {
2364 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002365 }
2366
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002367out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002368 thread__zput(trace->current);
2369
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002370 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002371
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002372 if (!err) {
2373 if (trace->summary)
2374 trace__fprintf_thread_summary(trace, trace->output);
2375
2376 if (trace->show_tool_stats) {
2377 fprintf(trace->output, "Stats:\n "
2378 " vfs_getname : %" PRIu64 "\n"
2379 " proc_getname: %" PRIu64 "\n",
2380 trace->stats.vfs_getname,
2381 trace->stats.proc_getname);
2382 }
2383 }
David Ahernbf2575c2013-10-08 21:26:53 -06002384
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002385out_delete_evlist:
2386 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002387 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002388 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002389 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002390{
2391 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002392
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002393out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002394 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002395 goto out_error;
2396
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002397out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002398 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002399 goto out_error;
2400
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002401out_error_mmap:
2402 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2403 goto out_error;
2404
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002405out_error_open:
2406 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2407
2408out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002409 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302410 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002411
2412out_error_apply_filters:
2413 fprintf(trace->output,
2414 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2415 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002416 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002417 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002418}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002419out_error_mem:
2420 fprintf(trace->output, "Not enough memory to run!\n");
2421 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002422
2423out_errno:
2424 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2425 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002426}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002427
David Ahern6810fc92013-08-28 22:29:52 -06002428static int trace__replay(struct trace *trace)
2429{
2430 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002431 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002432 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002433 struct perf_data_file file = {
2434 .path = input_name,
2435 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002436 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002437 };
David Ahern6810fc92013-08-28 22:29:52 -06002438 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002439 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002440 int err = -1;
2441
2442 trace->tool.sample = trace__process_sample;
2443 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002444 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002445 trace->tool.comm = perf_event__process_comm;
2446 trace->tool.exit = perf_event__process_exit;
2447 trace->tool.fork = perf_event__process_fork;
2448 trace->tool.attr = perf_event__process_attr;
2449 trace->tool.tracing_data = perf_event__process_tracing_data;
2450 trace->tool.build_id = perf_event__process_build_id;
2451
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002452 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002453 trace->tool.ordering_requires_timestamps = true;
2454
2455 /* add tid to output */
2456 trace->multiple_threads = true;
2457
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002458 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002459 if (session == NULL)
Taeung Song52e02832014-09-24 10:33:37 +09002460 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002461
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002462 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002463 goto out;
2464
David Ahern8fb598e2013-09-28 13:13:00 -06002465 trace->host = &session->machines.host;
2466
David Ahern6810fc92013-08-28 22:29:52 -06002467 err = perf_session__set_tracepoints_handlers(session, handlers);
2468 if (err)
2469 goto out;
2470
Namhyung Kim003824e2013-11-12 15:25:00 +09002471 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2472 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002473 /* older kernels have syscalls tp versus raw_syscalls */
2474 if (evsel == NULL)
2475 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2476 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002477
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002478 if (evsel &&
2479 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2480 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002481 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2482 goto out;
2483 }
2484
2485 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2486 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002487 if (evsel == NULL)
2488 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2489 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002490 if (evsel &&
2491 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2492 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002493 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002494 goto out;
2495 }
2496
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002497 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002498 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2499 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2500 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2501 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2502 evsel->handler = trace__pgfault;
2503 }
2504
David Ahernbdc89662013-08-28 22:29:53 -06002505 err = parse_target_str(trace);
2506 if (err != 0)
2507 goto out;
2508
David Ahern6810fc92013-08-28 22:29:52 -06002509 setup_pager();
2510
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002511 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002512 if (err)
2513 pr_err("Failed to process events, error %d", err);
2514
David Ahernbf2575c2013-10-08 21:26:53 -06002515 else if (trace->summary)
2516 trace__fprintf_thread_summary(trace, trace->output);
2517
David Ahern6810fc92013-08-28 22:29:52 -06002518out:
2519 perf_session__delete(session);
2520
2521 return err;
2522}
2523
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002524static size_t trace__fprintf_threads_header(FILE *fp)
2525{
2526 size_t printed;
2527
Pekka Enberg99ff7152013-11-12 16:42:14 +02002528 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002529
2530 return printed;
2531}
2532
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002533DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2534 struct stats *stats;
2535 double msecs;
2536 int syscall;
2537)
2538{
2539 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2540 struct stats *stats = source->priv;
2541
2542 entry->syscall = source->i;
2543 entry->stats = stats;
2544 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2545}
2546
David Ahernbf2575c2013-10-08 21:26:53 -06002547static size_t thread__dump_stats(struct thread_trace *ttrace,
2548 struct trace *trace, FILE *fp)
2549{
David Ahernbf2575c2013-10-08 21:26:53 -06002550 size_t printed = 0;
2551 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002552 struct rb_node *nd;
2553 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002554
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002555 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002556 return 0;
2557
2558 printed += fprintf(fp, "\n");
2559
Milian Wolff834fd462015-08-06 11:24:29 +02002560 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2561 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2562 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002563
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002564 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002565 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002566 if (stats) {
2567 double min = (double)(stats->min) / NSEC_PER_MSEC;
2568 double max = (double)(stats->max) / NSEC_PER_MSEC;
2569 double avg = avg_stats(stats);
2570 double pct;
2571 u64 n = (u64) stats->n;
2572
2573 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2574 avg /= NSEC_PER_MSEC;
2575
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002576 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002577 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002578 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002579 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002580 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002581 }
David Ahernbf2575c2013-10-08 21:26:53 -06002582 }
2583
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002584 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002585 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002586
2587 return printed;
2588}
2589
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002590static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002591{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002592 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002593 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002594 double ratio;
2595
2596 if (ttrace == NULL)
2597 return 0;
2598
2599 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2600
Pekka Enberg15e65c62013-11-14 18:43:30 +02002601 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002602 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002603 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002604 if (ttrace->pfmaj)
2605 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2606 if (ttrace->pfmin)
2607 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002608 if (trace->sched)
2609 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2610 else if (fputc('\n', fp) != EOF)
2611 ++printed;
2612
David Ahernbf2575c2013-10-08 21:26:53 -06002613 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002614
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002615 return printed;
2616}
David Ahern896cbb52013-09-28 13:12:59 -06002617
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002618static unsigned long thread__nr_events(struct thread_trace *ttrace)
2619{
2620 return ttrace ? ttrace->nr_events : 0;
2621}
2622
2623DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2624 struct thread *thread;
2625)
2626{
2627 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002628}
2629
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002630static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2631{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002632 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2633 size_t printed = trace__fprintf_threads_header(fp);
2634 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002635
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002636 if (threads == NULL) {
2637 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2638 return 0;
2639 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002640
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002641 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002642 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2643
2644 resort_rb__delete(threads);
2645
2646 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002647}
2648
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002649static int trace__set_duration(const struct option *opt, const char *str,
2650 int unset __maybe_unused)
2651{
2652 struct trace *trace = opt->value;
2653
2654 trace->duration_filter = atof(str);
2655 return 0;
2656}
2657
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002658static int trace__set_filter_pids(const struct option *opt, const char *str,
2659 int unset __maybe_unused)
2660{
2661 int ret = -1;
2662 size_t i;
2663 struct trace *trace = opt->value;
2664 /*
2665 * FIXME: introduce a intarray class, plain parse csv and create a
2666 * { int nr, int entries[] } struct...
2667 */
2668 struct intlist *list = intlist__new(str);
2669
2670 if (list == NULL)
2671 return -1;
2672
2673 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2674 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2675
2676 if (trace->filter_pids.entries == NULL)
2677 goto out;
2678
2679 trace->filter_pids.entries[0] = getpid();
2680
2681 for (i = 1; i < trace->filter_pids.nr; ++i)
2682 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2683
2684 intlist__delete(list);
2685 ret = 0;
2686out:
2687 return ret;
2688}
2689
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002690static int trace__open_output(struct trace *trace, const char *filename)
2691{
2692 struct stat st;
2693
2694 if (!stat(filename, &st) && st.st_size) {
2695 char oldname[PATH_MAX];
2696
2697 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2698 unlink(oldname);
2699 rename(filename, oldname);
2700 }
2701
2702 trace->output = fopen(filename, "w");
2703
2704 return trace->output == NULL ? -errno : 0;
2705}
2706
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002707static int parse_pagefaults(const struct option *opt, const char *str,
2708 int unset __maybe_unused)
2709{
2710 int *trace_pgfaults = opt->value;
2711
2712 if (strcmp(str, "all") == 0)
2713 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2714 else if (strcmp(str, "maj") == 0)
2715 *trace_pgfaults |= TRACE_PFMAJ;
2716 else if (strcmp(str, "min") == 0)
2717 *trace_pgfaults |= TRACE_PFMIN;
2718 else
2719 return -1;
2720
2721 return 0;
2722}
2723
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002724static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2725{
2726 struct perf_evsel *evsel;
2727
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002728 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002729 evsel->handler = handler;
2730}
2731
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002732int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2733{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002734 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002735 "perf trace [<options>] [<command>]",
2736 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002737 "perf trace record [<options>] [<command>]",
2738 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002739 NULL
2740 };
2741 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002742 .syscalls = {
2743 . max = -1,
2744 },
2745 .opts = {
2746 .target = {
2747 .uid = UINT_MAX,
2748 .uses_mmap = true,
2749 },
2750 .user_freq = UINT_MAX,
2751 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002752 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002753 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002754 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002755 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002756 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002757 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002758 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002759 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002760 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002761 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002762 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002763 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002764 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002765 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2766 "event selector. use 'perf list' to list available events",
2767 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002768 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2769 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002770 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002771 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002772 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002773 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002774 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2775 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002776 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002777 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002778 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2779 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002780 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002781 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002782 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002783 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002784 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002785 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002786 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2787 "number of mmap data pages",
2788 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002789 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002790 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002791 OPT_CALLBACK(0, "duration", &trace, "float",
2792 "show only events with duration > N.M ms",
2793 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002794 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002795 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002796 OPT_BOOLEAN('T', "time", &trace.full_time,
2797 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002798 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2799 "Show only syscall summary with statistics"),
2800 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2801 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002802 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2803 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002804 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002805 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002806 OPT_CALLBACK(0, "call-graph", &trace.opts,
2807 "record_mode[,record_size]", record_callchain_help,
2808 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002809 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2810 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002811 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2812 "Set the minimum stack depth when parsing the callchain, "
2813 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002814 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2815 "Set the maximum stack depth when parsing the callchain, "
2816 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002817 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002818 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2819 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002820 OPT_END()
2821 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002822 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002823 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002824 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002825 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002826 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002827
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002828 signal(SIGSEGV, sighandler_dump_stack);
2829 signal(SIGFPE, sighandler_dump_stack);
2830
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002831 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002832 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002833
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002834 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002835 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002836 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002837 goto out;
2838 }
2839
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002840 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2841 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002842
Wang Nand7888572016-04-08 15:07:24 +00002843 err = bpf__setup_stdout(trace.evlist);
2844 if (err) {
2845 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2846 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2847 goto out;
2848 }
2849
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002850 err = -1;
2851
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002852 if (trace.trace_pgfaults) {
2853 trace.opts.sample_address = true;
2854 trace.opts.sample_time = true;
2855 }
2856
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002857 if (trace.opts.mmap_pages == UINT_MAX)
2858 mmap_pages_user_set = false;
2859
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002860 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002861 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002862 max_stack_user_set = false;
2863 }
2864
2865#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002866 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002867 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2868#endif
2869
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002870 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002871 if (!mmap_pages_user_set && geteuid() == 0)
2872 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2873
Milian Wolff566a0882016-04-08 13:34:15 +02002874 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002875 }
Milian Wolff566a0882016-04-08 13:34:15 +02002876
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002877 if (trace.evlist->nr_entries > 0)
2878 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2879
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002880 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2881 return trace__record(&trace, argc-1, &argv[1]);
2882
2883 /* summary_only implies summary option, but don't overwrite summary if set */
2884 if (trace.summary_only)
2885 trace.summary = trace.summary_only;
2886
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002887 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2888 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002889 pr_err("Please specify something to trace.\n");
2890 return -1;
2891 }
2892
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002893 if (!trace.trace_syscalls && ev_qualifier_str) {
2894 pr_err("The -e option can't be used with --no-syscalls.\n");
2895 goto out;
2896 }
2897
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002898 if (output_name != NULL) {
2899 err = trace__open_output(&trace, output_name);
2900 if (err < 0) {
2901 perror("failed to create output file");
2902 goto out;
2903 }
2904 }
2905
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002906 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2907
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002908 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002909 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002910 struct strlist_config slist_config = {
2911 .dirname = system_path(STRACE_GROUPS_DIR),
2912 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002913
2914 trace.not_ev_qualifier = *s == '!';
2915 if (trace.not_ev_qualifier)
2916 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002917 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002918 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002919 fputs("Not enough memory to parse event qualifier",
2920 trace.output);
2921 err = -ENOMEM;
2922 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002923 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002924
2925 err = trace__validate_ev_qualifier(&trace);
2926 if (err)
2927 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002928 }
2929
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002930 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002931 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;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002935 }
2936
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002937 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002938 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002939 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002940 fprintf(trace.output, "%s", bf);
2941 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002942 }
2943
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002944 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002945 trace.opts.target.system_wide = true;
2946
David Ahern6810fc92013-08-28 22:29:52 -06002947 if (input_name)
2948 err = trace__replay(&trace);
2949 else
2950 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002951
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002952out_close:
2953 if (output_name != NULL)
2954 fclose(trace.output);
2955out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002956 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002957}