blob: 6e5c325148e488ec61a880196db9a7294d20156c [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/filter.h>
45#include <linux/audit.h>
46#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030047#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030048#include <linux/stringify.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030049
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030050#ifndef O_CLOEXEC
51# define O_CLOEXEC 02000000
52#endif
53
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030054struct trace {
55 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030056 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030057 struct {
58 int max;
59 struct syscall *table;
60 struct {
61 struct perf_evsel *sys_enter,
62 *sys_exit;
63 } events;
64 } syscalls;
65 struct record_opts opts;
66 struct perf_evlist *evlist;
67 struct machine *host;
68 struct thread *current;
69 u64 base_time;
70 FILE *output;
71 unsigned long nr_events;
72 struct strlist *ev_qualifier;
73 struct {
74 size_t nr;
75 int *entries;
76 } ev_qualifier_ids;
77 struct intlist *tid_list;
78 struct intlist *pid_list;
79 struct {
80 size_t nr;
81 pid_t *entries;
82 } filter_pids;
83 double duration_filter;
84 double runtime_ms;
85 struct {
86 u64 vfs_getname,
87 proc_getname;
88 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030089 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030090 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030091 bool not_ev_qualifier;
92 bool live;
93 bool full_time;
94 bool sched;
95 bool multiple_threads;
96 bool summary;
97 bool summary_only;
98 bool show_comm;
99 bool show_tool_stats;
100 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300101 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300102 bool force;
103 bool vfs_getname;
104 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300105 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300107
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300108struct tp_field {
109 int offset;
110 union {
111 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
112 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
113 };
114};
115
116#define TP_UINT_FIELD(bits) \
117static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
118{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500119 u##bits value; \
120 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
121 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300122}
123
124TP_UINT_FIELD(8);
125TP_UINT_FIELD(16);
126TP_UINT_FIELD(32);
127TP_UINT_FIELD(64);
128
129#define TP_UINT_FIELD__SWAPPED(bits) \
130static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
131{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500132 u##bits value; \
133 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300134 return bswap_##bits(value);\
135}
136
137TP_UINT_FIELD__SWAPPED(16);
138TP_UINT_FIELD__SWAPPED(32);
139TP_UINT_FIELD__SWAPPED(64);
140
141static int tp_field__init_uint(struct tp_field *field,
142 struct format_field *format_field,
143 bool needs_swap)
144{
145 field->offset = format_field->offset;
146
147 switch (format_field->size) {
148 case 1:
149 field->integer = tp_field__u8;
150 break;
151 case 2:
152 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
153 break;
154 case 4:
155 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
156 break;
157 case 8:
158 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
159 break;
160 default:
161 return -1;
162 }
163
164 return 0;
165}
166
167static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
168{
169 return sample->raw_data + field->offset;
170}
171
172static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
173{
174 field->offset = format_field->offset;
175 field->pointer = tp_field__ptr;
176 return 0;
177}
178
179struct syscall_tp {
180 struct tp_field id;
181 union {
182 struct tp_field args, ret;
183 };
184};
185
186static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
187 struct tp_field *field,
188 const char *name)
189{
190 struct format_field *format_field = perf_evsel__field(evsel, name);
191
192 if (format_field == NULL)
193 return -1;
194
195 return tp_field__init_uint(field, format_field, evsel->needs_swap);
196}
197
198#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
199 ({ struct syscall_tp *sc = evsel->priv;\
200 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
201
202static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
203 struct tp_field *field,
204 const char *name)
205{
206 struct format_field *format_field = perf_evsel__field(evsel, name);
207
208 if (format_field == NULL)
209 return -1;
210
211 return tp_field__init_ptr(field, format_field);
212}
213
214#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
215 ({ struct syscall_tp *sc = evsel->priv;\
216 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
217
218static void perf_evsel__delete_priv(struct perf_evsel *evsel)
219{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300220 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300221 perf_evsel__delete(evsel);
222}
223
Namhyung Kim96695d42013-11-12 08:51:45 -0300224static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
225{
226 evsel->priv = malloc(sizeof(struct syscall_tp));
227 if (evsel->priv != NULL) {
228 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
229 goto out_delete;
230
231 evsel->handler = handler;
232 return 0;
233 }
234
235 return -ENOMEM;
236
237out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300238 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300239 return -ENOENT;
240}
241
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300242static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300243{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245
David Ahern9aca7f12013-12-04 19:41:39 -0700246 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200247 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700248 evsel = perf_evsel__newtp("syscalls", direction);
249
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200250 if (IS_ERR(evsel))
251 return NULL;
252
253 if (perf_evsel__init_syscall_tp(evsel, handler))
254 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300255
256 return evsel;
257
258out_delete:
259 perf_evsel__delete_priv(evsel);
260 return NULL;
261}
262
263#define perf_evsel__sc_tp_uint(evsel, name, sample) \
264 ({ struct syscall_tp *fields = evsel->priv; \
265 fields->name.integer(&fields->name, sample); })
266
267#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
268 ({ struct syscall_tp *fields = evsel->priv; \
269 fields->name.pointer(&fields->name, sample); })
270
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271struct syscall_arg {
272 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300273 struct thread *thread;
274 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300275 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300276 u8 idx;
277 u8 mask;
278};
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300281 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282 int nr_entries;
283 const char **entries;
284};
285
286#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
287 .nr_entries = ARRAY_SIZE(array), \
288 .entries = array, \
289}
290
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300291#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
292 .offset = off, \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300297static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
298 const char *intfmt,
299 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300302 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303
304 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300305 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306
307 return scnprintf(bf, size, "%s", sa->entries[idx]);
308}
309
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300310static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
311 struct syscall_arg *arg)
312{
313 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
314}
315
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316#define SCA_STRARRAY syscall_arg__scnprintf_strarray
317
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300318#if defined(__i386__) || defined(__x86_64__)
319/*
320 * FIXME: Make this available to all arches as soon as the ioctl beautifier
321 * gets rewritten to support all arches.
322 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300323static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
324 struct syscall_arg *arg)
325{
326 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
327}
328
329#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300330#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300331
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300332static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
333 struct syscall_arg *arg);
334
335#define SCA_FD syscall_arg__scnprintf_fd
336
337static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
338 struct syscall_arg *arg)
339{
340 int fd = arg->val;
341
342 if (fd == AT_FDCWD)
343 return scnprintf(bf, size, "CWD");
344
345 return syscall_arg__scnprintf_fd(bf, size, arg);
346}
347
348#define SCA_FDAT syscall_arg__scnprintf_fd_at
349
350static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
351 struct syscall_arg *arg);
352
353#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
354
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300355static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300356 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300357{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300358 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300359}
360
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300361#define SCA_HEX syscall_arg__scnprintf_hex
362
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300363static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
364 struct syscall_arg *arg)
365{
366 return scnprintf(bf, size, "%d", arg->val);
367}
368
369#define SCA_INT syscall_arg__scnprintf_int
370
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300371static const char *bpf_cmd[] = {
372 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
373 "MAP_GET_NEXT_KEY", "PROG_LOAD",
374};
375static DEFINE_STRARRAY(bpf_cmd);
376
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300377static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
378static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300379
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300380static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
381static DEFINE_STRARRAY(itimers);
382
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300383static const char *keyctl_options[] = {
384 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
385 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
386 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
387 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
388 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
389};
390static DEFINE_STRARRAY(keyctl_options);
391
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300392static const char *whences[] = { "SET", "CUR", "END",
393#ifdef SEEK_DATA
394"DATA",
395#endif
396#ifdef SEEK_HOLE
397"HOLE",
398#endif
399};
400static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300401
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300402static const char *fcntl_cmds[] = {
403 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
404 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
405 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
406 "F_GETOWNER_UIDS",
407};
408static DEFINE_STRARRAY(fcntl_cmds);
409
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300410static const char *rlimit_resources[] = {
411 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
412 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
413 "RTTIME",
414};
415static DEFINE_STRARRAY(rlimit_resources);
416
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300417static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
418static DEFINE_STRARRAY(sighow);
419
David Ahern4f8c1b72013-09-22 19:45:00 -0600420static const char *clockid[] = {
421 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300422 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
423 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600424};
425static DEFINE_STRARRAY(clockid);
426
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300427static const char *socket_families[] = {
428 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
429 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
430 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
431 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
432 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
433 "ALG", "NFC", "VSOCK",
434};
435static DEFINE_STRARRAY(socket_families);
436
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300437static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
438 struct syscall_arg *arg)
439{
440 size_t printed = 0;
441 int mode = arg->val;
442
443 if (mode == F_OK) /* 0 */
444 return scnprintf(bf, size, "F");
445#define P_MODE(n) \
446 if (mode & n##_OK) { \
447 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
448 mode &= ~n##_OK; \
449 }
450
451 P_MODE(R);
452 P_MODE(W);
453 P_MODE(X);
454#undef P_MODE
455
456 if (mode)
457 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
458
459 return printed;
460}
461
462#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
463
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300464static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
465 struct syscall_arg *arg);
466
467#define SCA_FILENAME syscall_arg__scnprintf_filename
468
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300469static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
470 struct syscall_arg *arg)
471{
472 int printed = 0, flags = arg->val;
473
474#define P_FLAG(n) \
475 if (flags & O_##n) { \
476 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
477 flags &= ~O_##n; \
478 }
479
480 P_FLAG(CLOEXEC);
481 P_FLAG(NONBLOCK);
482#undef P_FLAG
483
484 if (flags)
485 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
486
487 return printed;
488}
489
490#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
491
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300492#if defined(__i386__) || defined(__x86_64__)
493/*
494 * FIXME: Make this available to all arches.
495 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300496#define TCGETS 0x5401
497
498static const char *tioctls[] = {
499 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
500 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
501 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
502 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
503 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
504 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
505 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
506 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
507 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
508 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
509 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
510 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
511 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
512 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
513 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
514};
515
516static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300517#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300518
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300519#ifndef GRND_NONBLOCK
520#define GRND_NONBLOCK 0x0001
521#endif
522#ifndef GRND_RANDOM
523#define GRND_RANDOM 0x0002
524#endif
525
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300526static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
527 struct syscall_arg *arg)
528{
529 int printed = 0, flags = arg->val;
530
531#define P_FLAG(n) \
532 if (flags & GRND_##n) { \
533 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
534 flags &= ~GRND_##n; \
535 }
536
537 P_FLAG(RANDOM);
538 P_FLAG(NONBLOCK);
539#undef P_FLAG
540
541 if (flags)
542 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
543
544 return printed;
545}
546
547#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
548
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300549#define STRARRAY(arg, name, array) \
550 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
551 .arg_parm = { [arg] = &strarray__##array, }
552
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300553#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300554#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300555#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300556#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300557#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300558#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300559#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300560#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300561#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300562#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300563#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300564#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300565#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300566#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300567
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300568static struct syscall_fmt {
569 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300570 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300571 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300572 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300573 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300574 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300575 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300576 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300577} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300578 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300579 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
580 [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300581 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300582 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300583 { .name = "brk", .hexret = true,
584 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300585 { .name = "chdir", .errmsg = true,
586 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
587 { .name = "chmod", .errmsg = true,
588 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
589 { .name = "chroot", .errmsg = true,
590 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
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 Melo34221112015-08-04 23:31:25 -0300596 { .name = "creat", .errmsg = true,
597 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300598 { .name = "dup", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300599 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300600 { .name = "dup2", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300601 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300602 { .name = "dup3", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300603 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300604 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300605 { .name = "eventfd2", .errmsg = true,
606 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300607 { .name = "faccessat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300608 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
609 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300610 { .name = "fadvise64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300611 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300612 { .name = "fallocate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300613 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300614 { .name = "fchdir", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300615 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300616 { .name = "fchmod", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300617 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300618 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300619 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
620 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300621 { .name = "fchown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300622 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300623 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300624 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
625 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300626 { .name = "fcntl", .errmsg = true,
627 .arg_scnprintf = { [0] = SCA_FD, /* fd */
628 [1] = SCA_STRARRAY, /* cmd */ },
629 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
630 { .name = "fdatasync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300631 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300632 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300633 .arg_scnprintf = { [0] = SCA_FD, /* fd */
634 [1] = SCA_FLOCK, /* cmd */ }, },
635 { .name = "fsetxattr", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300636 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300637 { .name = "fstat", .errmsg = true, .alias = "newfstat",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300638 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300639 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300640 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
641 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300642 { .name = "fstatfs", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300643 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300644 { .name = "fsync", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300645 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300646 { .name = "ftruncate", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300647 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300648 { .name = "futex", .errmsg = true,
649 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300650 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300651 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
652 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300653 { .name = "getdents", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300654 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300655 { .name = "getdents64", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300656 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300657 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300658 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300659 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300660 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300661 { .name = "getrandom", .errmsg = true,
662 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300663 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300664 { .name = "getxattr", .errmsg = true,
665 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
666 { .name = "inotify_add_watch", .errmsg = true,
667 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300668 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300669 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300670#if defined(__i386__) || defined(__x86_64__)
671/*
672 * FIXME: Make this available to all arches.
673 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300674 [1] = SCA_STRHEXARRAY, /* cmd */
675 [2] = SCA_HEX, /* arg */ },
676 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300677#else
678 [2] = SCA_HEX, /* arg */ }, },
679#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300680 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300681 { .name = "kill", .errmsg = true,
682 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300683 { .name = "lchown", .errmsg = true,
684 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
685 { .name = "lgetxattr", .errmsg = true,
686 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300687 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300688 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300689 { .name = "listxattr", .errmsg = true,
690 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300691 { .name = "llistxattr", .errmsg = true,
692 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
693 { .name = "lremovexattr", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300695 { .name = "lseek", .errmsg = true,
696 .arg_scnprintf = { [0] = SCA_FD, /* fd */
697 [2] = SCA_STRARRAY, /* whence */ },
698 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300699 { .name = "lsetxattr", .errmsg = true,
700 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300701 { .name = "lstat", .errmsg = true, .alias = "newlstat",
702 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300703 { .name = "lsxattr", .errmsg = true,
704 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300705 { .name = "madvise", .errmsg = true,
706 .arg_scnprintf = { [0] = SCA_HEX, /* start */
707 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300708 { .name = "mkdir", .errmsg = true,
709 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300710 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300711 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
712 [1] = SCA_FILENAME, /* pathname */ }, },
713 { .name = "mknod", .errmsg = true,
714 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300715 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300716 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
717 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300718 { .name = "mlock", .errmsg = true,
719 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
720 { .name = "mlockall", .errmsg = true,
721 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300722 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300723 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300724 [2] = SCA_MMAP_PROT, /* prot */
Namhyung Kim73faab32013-11-12 15:24:59 +0900725 [3] = SCA_MMAP_FLAGS, /* flags */
726 [4] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300727 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300728 .arg_scnprintf = { [0] = SCA_HEX, /* start */
729 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300730 { .name = "mq_unlink", .errmsg = true,
731 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300732 { .name = "mremap", .hexret = true,
733 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300734 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300735 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300736 { .name = "munlock", .errmsg = true,
737 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300738 { .name = "munmap", .errmsg = true,
739 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300740 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300741 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300742 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300743 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
744 [1] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300745 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300746 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
747 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300748 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300749 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
750 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300751 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300752 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300753 [1] = SCA_FILENAME, /* filename */
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300754 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300755 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300756 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300757 [3] = SCA_FD, /* group_fd */
758 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300759 { .name = "pipe2", .errmsg = true,
760 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300761 { .name = "poll", .errmsg = true, .timeout = true, },
762 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300763 { .name = "pread", .errmsg = true, .alias = "pread64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300764 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300765 { .name = "preadv", .errmsg = true, .alias = "pread",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300766 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300767 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300768 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300769 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300770 { .name = "pwritev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300771 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300772 { .name = "read", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300773 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300774 { .name = "readlink", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300776 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300777 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
778 [1] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300779 { .name = "readv", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300780 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300781 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300782 .arg_scnprintf = { [0] = SCA_FD, /* fd */
783 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300784 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300785 .arg_scnprintf = { [0] = SCA_FD, /* fd */
786 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300787 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300788 .arg_scnprintf = { [0] = SCA_FD, /* fd */
789 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300790 { .name = "removexattr", .errmsg = true,
791 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300792 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300793 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300794 { .name = "rmdir", .errmsg = true,
795 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300796 { .name = "rt_sigaction", .errmsg = true,
797 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300798 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300799 { .name = "rt_sigqueueinfo", .errmsg = true,
800 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
801 { .name = "rt_tgsigqueueinfo", .errmsg = true,
802 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300803 { .name = "sched_setscheduler", .errmsg = true,
804 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300805 { .name = "seccomp", .errmsg = true,
806 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
807 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300808 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300809 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300810 .arg_scnprintf = { [0] = SCA_FD, /* fd */
811 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300812 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300813 .arg_scnprintf = { [0] = SCA_FD, /* fd */
814 [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300815 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo8d8c66a2015-08-11 10:57:02 -0300816 .arg_scnprintf = { [0] = SCA_FD, /* fd */
817 [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300818 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300819 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300820 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300821 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300822 { .name = "setxattr", .errmsg = true,
823 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300824 { .name = "shutdown", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300825 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300826 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300827 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
828 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300829 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300830 { .name = "socketpair", .errmsg = true,
831 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
832 [1] = SCA_SK_TYPE, /* type */ },
833 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300834 { .name = "stat", .errmsg = true, .alias = "newstat",
835 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300836 { .name = "statfs", .errmsg = true,
837 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
838 { .name = "swapoff", .errmsg = true,
839 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
840 { .name = "swapon", .errmsg = true,
841 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300842 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300843 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300844 { .name = "tgkill", .errmsg = true,
845 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
846 { .name = "tkill", .errmsg = true,
847 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300848 { .name = "truncate", .errmsg = true,
849 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300850 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300851 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300852 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
853 [1] = SCA_FILENAME, /* pathname */ }, },
854 { .name = "utime", .errmsg = true,
855 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300856 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300857 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
858 [1] = SCA_FILENAME, /* filename */ }, },
859 { .name = "utimes", .errmsg = true,
860 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300861 { .name = "vmsplice", .errmsg = true,
862 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300863 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300864 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300865 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300866 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300867 { .name = "write", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300868 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300869 { .name = "writev", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300870 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300871};
872
873static int syscall_fmt__cmp(const void *name, const void *fmtp)
874{
875 const struct syscall_fmt *fmt = fmtp;
876 return strcmp(name, fmt->name);
877}
878
879static struct syscall_fmt *syscall_fmt__find(const char *name)
880{
881 const int nmemb = ARRAY_SIZE(syscall_fmts);
882 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
883}
884
885struct syscall {
886 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300887 int nr_args;
888 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300889 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300890 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300891 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300892 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300893 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300894};
895
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200896static size_t fprintf_duration(unsigned long t, FILE *fp)
897{
898 double duration = (double)t / NSEC_PER_MSEC;
899 size_t printed = fprintf(fp, "(");
900
901 if (duration >= 1.0)
902 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
903 else if (duration >= 0.01)
904 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
905 else
906 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300907 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200908}
909
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300910/**
911 * filename.ptr: The filename char pointer that will be vfs_getname'd
912 * filename.entry_str_pos: Where to insert the string translated from
913 * filename.ptr by the vfs_getname tracepoint/kprobe.
914 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300915struct thread_trace {
916 u64 entry_time;
917 u64 exit_time;
918 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300919 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400920 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300921 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300922 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300923 struct {
924 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300925 short int entry_str_pos;
926 bool pending_open;
927 unsigned int namelen;
928 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300929 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300930 struct {
931 int max;
932 char **table;
933 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600934
935 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300936};
937
938static struct thread_trace *thread_trace__new(void)
939{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300940 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
941
942 if (ttrace)
943 ttrace->paths.max = -1;
944
David Ahernbf2575c2013-10-08 21:26:53 -0600945 ttrace->syscall_stats = intlist__new(NULL);
946
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300947 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300948}
949
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300950static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300951{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300952 struct thread_trace *ttrace;
953
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300954 if (thread == NULL)
955 goto fail;
956
Namhyung Kim89dceb22014-10-06 09:46:03 +0900957 if (thread__priv(thread) == NULL)
958 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300959
Namhyung Kim89dceb22014-10-06 09:46:03 +0900960 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300961 goto fail;
962
Namhyung Kim89dceb22014-10-06 09:46:03 +0900963 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300964 ++ttrace->nr_events;
965
966 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300967fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300968 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300969 "WARNING: not enough memory, dropping samples!\n");
970 return NULL;
971}
972
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400973#define TRACE_PFMAJ (1 << 0)
974#define TRACE_PFMIN (1 << 1)
975
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300976static const size_t trace__entry_str_size = 2048;
977
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300978static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300979{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900980 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981
982 if (fd > ttrace->paths.max) {
983 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
984
985 if (npath == NULL)
986 return -1;
987
988 if (ttrace->paths.max != -1) {
989 memset(npath + ttrace->paths.max + 1, 0,
990 (fd - ttrace->paths.max) * sizeof(char *));
991 } else {
992 memset(npath, 0, (fd + 1) * sizeof(char *));
993 }
994
995 ttrace->paths.table = npath;
996 ttrace->paths.max = fd;
997 }
998
999 ttrace->paths.table[fd] = strdup(pathname);
1000
1001 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1002}
1003
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001004static int thread__read_fd_path(struct thread *thread, int fd)
1005{
1006 char linkname[PATH_MAX], pathname[PATH_MAX];
1007 struct stat st;
1008 int ret;
1009
1010 if (thread->pid_ == thread->tid) {
1011 scnprintf(linkname, sizeof(linkname),
1012 "/proc/%d/fd/%d", thread->pid_, fd);
1013 } else {
1014 scnprintf(linkname, sizeof(linkname),
1015 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1016 }
1017
1018 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1019 return -1;
1020
1021 ret = readlink(linkname, pathname, sizeof(pathname));
1022
1023 if (ret < 0 || ret > st.st_size)
1024 return -1;
1025
1026 pathname[ret] = '\0';
1027 return trace__set_fd_pathname(thread, fd, pathname);
1028}
1029
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001030static const char *thread__fd_path(struct thread *thread, int fd,
1031 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001032{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001033 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001034
1035 if (ttrace == NULL)
1036 return NULL;
1037
1038 if (fd < 0)
1039 return NULL;
1040
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001041 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001042 if (!trace->live)
1043 return NULL;
1044 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001045 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001046 return NULL;
1047 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048
1049 return ttrace->paths.table[fd];
1050}
1051
1052static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1053 struct syscall_arg *arg)
1054{
1055 int fd = arg->val;
1056 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001057 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001058
1059 if (path)
1060 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1061
1062 return printed;
1063}
1064
1065static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1066 struct syscall_arg *arg)
1067{
1068 int fd = arg->val;
1069 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001070 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001071
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001072 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1073 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001074
1075 return printed;
1076}
1077
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001078static void thread__set_filename_pos(struct thread *thread, const char *bf,
1079 unsigned long ptr)
1080{
1081 struct thread_trace *ttrace = thread__priv(thread);
1082
1083 ttrace->filename.ptr = ptr;
1084 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1085}
1086
1087static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1088 struct syscall_arg *arg)
1089{
1090 unsigned long ptr = arg->val;
1091
1092 if (!arg->trace->vfs_getname)
1093 return scnprintf(bf, size, "%#x", ptr);
1094
1095 thread__set_filename_pos(arg->thread, bf, ptr);
1096 return 0;
1097}
1098
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001099static bool trace__filter_duration(struct trace *trace, double t)
1100{
1101 return t < (trace->duration_filter * NSEC_PER_MSEC);
1102}
1103
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1105{
1106 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1107
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001108 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109}
1110
Namhyung Kimf15eb532012-10-05 14:02:16 +09001111static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001112static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001113
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001114static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001115{
1116 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001117 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001118}
1119
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001121 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122{
1123 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001124 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001126 if (trace->multiple_threads) {
1127 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001128 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001129 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001130 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131
1132 return printed;
1133}
1134
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001135static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001136 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137{
1138 int ret = 0;
1139
1140 switch (event->header.type) {
1141 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001142 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001143 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001144 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001145 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001147 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 break;
1149 }
1150
1151 return ret;
1152}
1153
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001154static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001156 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157 struct machine *machine)
1158{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001159 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001160 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001161}
1162
1163static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1164{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001165 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001166
1167 if (err)
1168 return err;
1169
David Ahern8fb598e2013-09-28 13:13:00 -06001170 trace->host = machine__new_host();
1171 if (trace->host == NULL)
1172 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001173
Arnaldo Carvalho de Melo959c2192015-07-24 12:13:05 -03001174 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001175 return -errno;
1176
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001177 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001178 evlist->threads, trace__tool_process, false,
1179 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001180 if (err)
1181 symbol__exit();
1182
1183 return err;
1184}
1185
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001186static int syscall__set_arg_fmts(struct syscall *sc)
1187{
1188 struct format_field *field;
1189 int idx = 0;
1190
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001191 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001192 if (sc->arg_scnprintf == NULL)
1193 return -1;
1194
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001195 if (sc->fmt)
1196 sc->arg_parm = sc->fmt->arg_parm;
1197
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001198 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001199 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1200 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1201 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001202 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001203 else if (strcmp(field->type, "pid_t") == 0)
1204 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001205 else if (strcmp(field->type, "umode_t") == 0)
1206 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001207 ++idx;
1208 }
1209
1210 return 0;
1211}
1212
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001213static int trace__read_syscall_info(struct trace *trace, int id)
1214{
1215 char tp_name[128];
1216 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001217 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001218
1219 if (name == NULL)
1220 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001221
1222 if (id > trace->syscalls.max) {
1223 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1224
1225 if (nsyscalls == NULL)
1226 return -1;
1227
1228 if (trace->syscalls.max != -1) {
1229 memset(nsyscalls + trace->syscalls.max + 1, 0,
1230 (id - trace->syscalls.max) * sizeof(*sc));
1231 } else {
1232 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1233 }
1234
1235 trace->syscalls.table = nsyscalls;
1236 trace->syscalls.max = id;
1237 }
1238
1239 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001240 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001241
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001242 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001243
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001244 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001245 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001246
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001247 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001248 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001249 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001250 }
1251
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001252 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001253 return -1;
1254
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001255 sc->args = sc->tp_format->format.fields;
1256 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001257 /*
1258 * We need to check and discard the first variable '__syscall_nr'
1259 * or 'nr' that mean the syscall number. It is needless here.
1260 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1261 */
1262 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001263 sc->args = sc->args->next;
1264 --sc->nr_args;
1265 }
1266
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001267 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1268
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001269 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001270}
1271
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001272static int trace__validate_ev_qualifier(struct trace *trace)
1273{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001274 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001275 struct str_node *pos;
1276
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001277 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1278 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1279 sizeof(trace->ev_qualifier_ids.entries[0]));
1280
1281 if (trace->ev_qualifier_ids.entries == NULL) {
1282 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1283 trace->output);
1284 err = -EINVAL;
1285 goto out;
1286 }
1287
1288 i = 0;
1289
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001290 strlist__for_each(pos, trace->ev_qualifier) {
1291 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001292 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001293
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001294 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001295 if (err == 0) {
1296 fputs("Error:\tInvalid syscall ", trace->output);
1297 err = -EINVAL;
1298 } else {
1299 fputs(", ", trace->output);
1300 }
1301
1302 fputs(sc, trace->output);
1303 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001304
1305 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001306 }
1307
1308 if (err < 0) {
1309 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1310 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001311 zfree(&trace->ev_qualifier_ids.entries);
1312 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001313 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001314out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001315 return err;
1316}
1317
David Ahern55d43bca2015-02-19 15:00:22 -05001318/*
1319 * args is to be interpreted as a series of longs but we need to handle
1320 * 8-byte unaligned accesses. args points to raw_data within the event
1321 * and raw_data is guaranteed to be 8-byte unaligned because it is
1322 * preceded by raw_size which is a u32. So we need to copy args to a temp
1323 * variable to read it. Most notably this avoids extended load instructions
1324 * on unaligned addresses
1325 */
1326
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001327static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001328 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001329 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001330{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001331 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001332 unsigned char *p;
1333 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001334
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001335 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001336 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001337 u8 bit = 1;
1338 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001339 .idx = 0,
1340 .mask = 0,
1341 .trace = trace,
1342 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001343 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001344
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001345 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001346 field = field->next, ++arg.idx, bit <<= 1) {
1347 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001348 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001349
1350 /* special care for unaligned accesses */
1351 p = args + sizeof(unsigned long) * arg.idx;
1352 memcpy(&val, p, sizeof(val));
1353
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001354 /*
1355 * Suppress this argument if its value is zero and
1356 * and we don't have a string associated in an
1357 * strarray for it.
1358 */
David Ahern55d43bca2015-02-19 15:00:22 -05001359 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001360 !(sc->arg_scnprintf &&
1361 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1362 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001363 continue;
1364
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001365 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001366 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001367 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001368 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001369 if (sc->arg_parm)
1370 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001371 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1372 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001373 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001374 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001375 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001376 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001377 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001378 } else if (IS_ERR(sc->tp_format)) {
1379 /*
1380 * If we managed to read the tracepoint /format file, then we
1381 * may end up not having any args, like with gettid(), so only
1382 * print the raw args when we didn't manage to read it.
1383 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001384 int i = 0;
1385
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001387 /* special care for unaligned accesses */
1388 p = args + sizeof(unsigned long) * i;
1389 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001390 printed += scnprintf(bf + printed, size - printed,
1391 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001392 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001393 ++i;
1394 }
1395 }
1396
1397 return printed;
1398}
1399
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001400typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001401 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001402 struct perf_sample *sample);
1403
1404static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001405 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001406{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001407
1408 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001409
1410 /*
1411 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1412 * before that, leaving at a higher verbosity level till that is
1413 * explained. Reproduced with plain ftrace with:
1414 *
1415 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1416 * grep "NR -1 " /t/trace_pipe
1417 *
1418 * After generating some load on the machine.
1419 */
1420 if (verbose > 1) {
1421 static u64 n;
1422 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1423 id, perf_evsel__name(evsel), ++n);
1424 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001425 return NULL;
1426 }
1427
1428 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1429 trace__read_syscall_info(trace, id))
1430 goto out_cant_read;
1431
1432 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1433 goto out_cant_read;
1434
1435 return &trace->syscalls.table[id];
1436
1437out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001438 if (verbose) {
1439 fprintf(trace->output, "Problems reading syscall %d", id);
1440 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1441 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1442 fputs(" information\n", trace->output);
1443 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001444 return NULL;
1445}
1446
David Ahernbf2575c2013-10-08 21:26:53 -06001447static void thread__update_stats(struct thread_trace *ttrace,
1448 int id, struct perf_sample *sample)
1449{
1450 struct int_node *inode;
1451 struct stats *stats;
1452 u64 duration = 0;
1453
1454 inode = intlist__findnew(ttrace->syscall_stats, id);
1455 if (inode == NULL)
1456 return;
1457
1458 stats = inode->priv;
1459 if (stats == NULL) {
1460 stats = malloc(sizeof(struct stats));
1461 if (stats == NULL)
1462 return;
1463 init_stats(stats);
1464 inode->priv = stats;
1465 }
1466
1467 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1468 duration = sample->time - ttrace->entry_time;
1469
1470 update_stats(stats, duration);
1471}
1472
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001473static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1474{
1475 struct thread_trace *ttrace;
1476 u64 duration;
1477 size_t printed;
1478
1479 if (trace->current == NULL)
1480 return 0;
1481
1482 ttrace = thread__priv(trace->current);
1483
1484 if (!ttrace->entry_pending)
1485 return 0;
1486
1487 duration = sample->time - ttrace->entry_time;
1488
1489 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1490 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1491 ttrace->entry_pending = false;
1492
1493 return printed;
1494}
1495
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001496static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001497 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001498 struct perf_sample *sample)
1499{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001500 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001501 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001502 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001503 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001504 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001505 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001506 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001507
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001508 if (sc == NULL)
1509 return -1;
1510
David Ahern8fb598e2013-09-28 13:13:00 -06001511 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001512 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001513 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001514 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001515
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001516 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001517
1518 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001519 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001521 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001522 }
1523
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001524 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001525 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001526
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001527 ttrace->entry_time = sample->time;
1528 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001529 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001530
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001531 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001532 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001533
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001534 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001535 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001536 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1537 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001538 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001539 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001540 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001541 /* See trace__vfs_getname & trace__sys_exit */
1542 ttrace->filename.pending_open = false;
1543 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001544
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001545 if (trace->current != thread) {
1546 thread__put(trace->current);
1547 trace->current = thread__get(thread);
1548 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001549 err = 0;
1550out_put:
1551 thread__put(thread);
1552 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001553}
1554
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001555static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1556 struct perf_sample *sample,
1557 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001558{
1559 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001560
1561 if (machine__resolve(trace->host, &al, sample) < 0 ||
1562 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1563 return -1;
1564
1565 return 0;
1566}
1567
1568static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1569{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001570 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001571 const unsigned int print_opts = EVSEL__PRINT_SYM |
1572 EVSEL__PRINT_DSO |
1573 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001574
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001575 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001576}
1577
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001578static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001579 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001580 struct perf_sample *sample)
1581{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001582 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001583 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001584 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001585 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001586 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001587 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001588
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001589 if (sc == NULL)
1590 return -1;
1591
David Ahern8fb598e2013-09-28 13:13:00 -06001592 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001593 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001594 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001595 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001596
David Ahernbf2575c2013-10-08 21:26:53 -06001597 if (trace->summary)
1598 thread__update_stats(ttrace, id, sample);
1599
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001600 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001601
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001602 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001603 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1604 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001605 ++trace->stats.vfs_getname;
1606 }
1607
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001608 ttrace->exit_time = sample->time;
1609
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001610 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001611 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001612 if (trace__filter_duration(trace, duration))
1613 goto out;
1614 } else if (trace->duration_filter)
1615 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001616
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001617 if (sample->callchain) {
1618 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1619 if (callchain_ret == 0) {
1620 if (callchain_cursor.nr < trace->min_stack)
1621 goto out;
1622 callchain_ret = 1;
1623 }
1624 }
1625
David Ahernfd2eaba2013-11-12 09:31:15 -07001626 if (trace->summary_only)
1627 goto out;
1628
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001629 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001630
1631 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001632 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001633 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001634 fprintf(trace->output, " ... [");
1635 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1636 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001637 }
1638
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001639 if (sc->fmt == NULL) {
1640signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001641 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001642 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001643 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001644 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1645 *e = audit_errno_to_name(-ret);
1646
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001647 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001648 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001649 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001650 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001651 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001652 else if (sc->fmt->errpid) {
1653 struct thread *child = machine__find_thread(trace->host, ret, ret);
1654
1655 if (child != NULL) {
1656 fprintf(trace->output, ") = %ld", ret);
1657 if (child->comm_set)
1658 fprintf(trace->output, " (%s)", thread__comm_str(child));
1659 thread__put(child);
1660 }
1661 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001662 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001663
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001665
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001666 if (callchain_ret > 0)
1667 trace__fprintf_callchain(trace, sample);
1668 else if (callchain_ret < 0)
1669 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001670out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001672 err = 0;
1673out_put:
1674 thread__put(thread);
1675 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001676}
1677
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001678static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001679 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001680 struct perf_sample *sample)
1681{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001682 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1683 struct thread_trace *ttrace;
1684 size_t filename_len, entry_str_len, to_move;
1685 ssize_t remaining_space;
1686 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001687 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001688
1689 if (!thread)
1690 goto out;
1691
1692 ttrace = thread__priv(thread);
1693 if (!ttrace)
1694 goto out;
1695
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001696 filename_len = strlen(filename);
1697
1698 if (ttrace->filename.namelen < filename_len) {
1699 char *f = realloc(ttrace->filename.name, filename_len + 1);
1700
1701 if (f == NULL)
1702 goto out;
1703
1704 ttrace->filename.namelen = filename_len;
1705 ttrace->filename.name = f;
1706 }
1707
1708 strcpy(ttrace->filename.name, filename);
1709 ttrace->filename.pending_open = true;
1710
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001711 if (!ttrace->filename.ptr)
1712 goto out;
1713
1714 entry_str_len = strlen(ttrace->entry_str);
1715 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1716 if (remaining_space <= 0)
1717 goto out;
1718
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001719 if (filename_len > (size_t)remaining_space) {
1720 filename += filename_len - remaining_space;
1721 filename_len = remaining_space;
1722 }
1723
1724 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1725 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1726 memmove(pos + filename_len, pos, to_move);
1727 memcpy(pos, filename, filename_len);
1728
1729 ttrace->filename.ptr = 0;
1730 ttrace->filename.entry_str_pos = 0;
1731out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001732 return 0;
1733}
1734
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001735static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001736 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001737 struct perf_sample *sample)
1738{
1739 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1740 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001741 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001742 sample->pid,
1743 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001744 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001745
1746 if (ttrace == NULL)
1747 goto out_dump;
1748
1749 ttrace->runtime_ms += runtime_ms;
1750 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001751 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001752 return 0;
1753
1754out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001755 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001756 evsel->name,
1757 perf_evsel__strval(evsel, sample, "comm"),
1758 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1759 runtime,
1760 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001761 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001762 return 0;
1763}
1764
Wang Nan1d6c9402016-02-26 09:31:55 +00001765static void bpf_output__printer(enum binary_printer_ops op,
1766 unsigned int val, void *extra)
1767{
1768 FILE *output = extra;
1769 unsigned char ch = (unsigned char)val;
1770
1771 switch (op) {
1772 case BINARY_PRINT_CHAR_DATA:
1773 fprintf(output, "%c", isprint(ch) ? ch : '.');
1774 break;
1775 case BINARY_PRINT_DATA_BEGIN:
1776 case BINARY_PRINT_LINE_BEGIN:
1777 case BINARY_PRINT_ADDR:
1778 case BINARY_PRINT_NUM_DATA:
1779 case BINARY_PRINT_NUM_PAD:
1780 case BINARY_PRINT_SEP:
1781 case BINARY_PRINT_CHAR_PAD:
1782 case BINARY_PRINT_LINE_END:
1783 case BINARY_PRINT_DATA_END:
1784 default:
1785 break;
1786 }
1787}
1788
1789static void bpf_output__fprintf(struct trace *trace,
1790 struct perf_sample *sample)
1791{
1792 print_binary(sample->raw_data, sample->raw_size, 8,
1793 bpf_output__printer, trace->output);
1794}
1795
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001796static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1797 union perf_event *event __maybe_unused,
1798 struct perf_sample *sample)
1799{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001800 int callchain_ret = 0;
1801
1802 if (sample->callchain) {
1803 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1804 if (callchain_ret == 0) {
1805 if (callchain_cursor.nr < trace->min_stack)
1806 goto out;
1807 callchain_ret = 1;
1808 }
1809 }
1810
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001811 trace__printf_interrupted_entry(trace, sample);
1812 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001813
1814 if (trace->trace_syscalls)
1815 fprintf(trace->output, "( ): ");
1816
1817 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001818
Wang Nan1d6c9402016-02-26 09:31:55 +00001819 if (perf_evsel__is_bpf_output(evsel)) {
1820 bpf_output__fprintf(trace, sample);
1821 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001822 event_format__fprintf(evsel->tp_format, sample->cpu,
1823 sample->raw_data, sample->raw_size,
1824 trace->output);
1825 }
1826
1827 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001828
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001829 if (callchain_ret > 0)
1830 trace__fprintf_callchain(trace, sample);
1831 else if (callchain_ret < 0)
1832 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1833out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001834 return 0;
1835}
1836
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001837static void print_location(FILE *f, struct perf_sample *sample,
1838 struct addr_location *al,
1839 bool print_dso, bool print_sym)
1840{
1841
1842 if ((verbose || print_dso) && al->map)
1843 fprintf(f, "%s@", al->map->dso->long_name);
1844
1845 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001846 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001847 al->addr - al->sym->start);
1848 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001849 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001850 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001851 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001852}
1853
1854static int trace__pgfault(struct trace *trace,
1855 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001856 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001857 struct perf_sample *sample)
1858{
1859 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001860 struct addr_location al;
1861 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001862 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001863 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001864 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001865
1866 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001867
1868 if (sample->callchain) {
1869 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1870 if (callchain_ret == 0) {
1871 if (callchain_cursor.nr < trace->min_stack)
1872 goto out_put;
1873 callchain_ret = 1;
1874 }
1875 }
1876
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001877 ttrace = thread__trace(thread, trace->output);
1878 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001879 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001880
1881 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1882 ttrace->pfmaj++;
1883 else
1884 ttrace->pfmin++;
1885
1886 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001887 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001889 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001890 sample->ip, &al);
1891
1892 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1893
1894 fprintf(trace->output, "%sfault [",
1895 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1896 "maj" : "min");
1897
1898 print_location(trace->output, sample, &al, false, true);
1899
1900 fprintf(trace->output, "] => ");
1901
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001902 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001903 sample->addr, &al);
1904
1905 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001906 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001907 MAP__FUNCTION, sample->addr, &al);
1908
1909 if (al.map)
1910 map_type = 'x';
1911 else
1912 map_type = '?';
1913 }
1914
1915 print_location(trace->output, sample, &al, true, false);
1916
1917 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001918
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001919 if (callchain_ret > 0)
1920 trace__fprintf_callchain(trace, sample);
1921 else if (callchain_ret < 0)
1922 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001923out:
1924 err = 0;
1925out_put:
1926 thread__put(thread);
1927 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001928}
1929
David Ahernbdc89662013-08-28 22:29:53 -06001930static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1931{
1932 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1933 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1934 return false;
1935
1936 if (trace->pid_list || trace->tid_list)
1937 return true;
1938
1939 return false;
1940}
1941
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001942static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001943 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001944 struct perf_sample *sample)
1945{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001946 /*
1947 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1948 * and don't use sample->time unconditionally, we may end up having
1949 * some other event in the future without PERF_SAMPLE_TIME for good
1950 * reason, i.e. we may not be interested in its timestamps, just in
1951 * it taking place, picking some piece of information when it
1952 * appears in our event stream (vfs_getname comes to mind).
1953 */
1954 if (trace->base_time == 0 && !trace->full_time &&
1955 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001956 trace->base_time = sample->time;
1957}
1958
David Ahern6810fc92013-08-28 22:29:52 -06001959static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001960 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001961 struct perf_sample *sample,
1962 struct perf_evsel *evsel,
1963 struct machine *machine __maybe_unused)
1964{
1965 struct trace *trace = container_of(tool, struct trace, tool);
1966 int err = 0;
1967
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001968 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001969
David Ahernbdc89662013-08-28 22:29:53 -06001970 if (skip_sample(trace, sample))
1971 return 0;
1972
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001973 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001974
David Ahern31605652013-12-04 19:41:41 -07001975 if (handler) {
1976 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001977 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001978 }
David Ahern6810fc92013-08-28 22:29:52 -06001979
1980 return err;
1981}
1982
David Ahernbdc89662013-08-28 22:29:53 -06001983static int parse_target_str(struct trace *trace)
1984{
1985 if (trace->opts.target.pid) {
1986 trace->pid_list = intlist__new(trace->opts.target.pid);
1987 if (trace->pid_list == NULL) {
1988 pr_err("Error parsing process id string\n");
1989 return -EINVAL;
1990 }
1991 }
1992
1993 if (trace->opts.target.tid) {
1994 trace->tid_list = intlist__new(trace->opts.target.tid);
1995 if (trace->tid_list == NULL) {
1996 pr_err("Error parsing thread id string\n");
1997 return -EINVAL;
1998 }
1999 }
2000
2001 return 0;
2002}
2003
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002004static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002005{
2006 unsigned int rec_argc, i, j;
2007 const char **rec_argv;
2008 const char * const record_args[] = {
2009 "record",
2010 "-R",
2011 "-m", "1024",
2012 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002013 };
2014
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002015 const char * const sc_args[] = { "-e", };
2016 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2017 const char * const majpf_args[] = { "-e", "major-faults" };
2018 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2019 const char * const minpf_args[] = { "-e", "minor-faults" };
2020 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2021
David Ahern9aca7f12013-12-04 19:41:39 -07002022 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002023 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2024 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002025 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2026
2027 if (rec_argv == NULL)
2028 return -ENOMEM;
2029
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002030 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002031 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002032 rec_argv[j++] = record_args[i];
2033
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002034 if (trace->trace_syscalls) {
2035 for (i = 0; i < sc_args_nr; i++)
2036 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002037
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002038 /* event string may be different for older kernels - e.g., RHEL6 */
2039 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2040 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2041 else if (is_valid_tracepoint("syscalls:sys_enter"))
2042 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2043 else {
2044 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2045 return -1;
2046 }
David Ahern9aca7f12013-12-04 19:41:39 -07002047 }
David Ahern9aca7f12013-12-04 19:41:39 -07002048
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002049 if (trace->trace_pgfaults & TRACE_PFMAJ)
2050 for (i = 0; i < majpf_args_nr; i++)
2051 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002052
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002053 if (trace->trace_pgfaults & TRACE_PFMIN)
2054 for (i = 0; i < minpf_args_nr; i++)
2055 rec_argv[j++] = minpf_args[i];
2056
2057 for (i = 0; i < (unsigned int)argc; i++)
2058 rec_argv[j++] = argv[i];
2059
2060 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002061}
2062
David Ahernbf2575c2013-10-08 21:26:53 -06002063static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2064
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002065static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002066{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002067 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002068
2069 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002070 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002071
2072 if (perf_evsel__field(evsel, "pathname") == NULL) {
2073 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002074 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002075 }
2076
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002077 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002078 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002079 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002080}
2081
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002082static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002083{
2084 struct perf_evsel *evsel;
2085 struct perf_event_attr attr = {
2086 .type = PERF_TYPE_SOFTWARE,
2087 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002088 };
2089
2090 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002091 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002092
2093 event_attr_init(&attr);
2094
2095 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002096 if (evsel)
2097 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002098
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002099 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002100}
2101
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002102static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2103{
2104 const u32 type = event->header.type;
2105 struct perf_evsel *evsel;
2106
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002107 if (type != PERF_RECORD_SAMPLE) {
2108 trace__process_event(trace, trace->host, event, sample);
2109 return;
2110 }
2111
2112 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2113 if (evsel == NULL) {
2114 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2115 return;
2116 }
2117
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002118 trace__set_base_time(trace, evsel, sample);
2119
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002120 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2121 sample->raw_data == NULL) {
2122 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2123 perf_evsel__name(evsel), sample->tid,
2124 sample->cpu, sample->raw_size);
2125 } else {
2126 tracepoint_handler handler = evsel->handler;
2127 handler(trace, evsel, event, sample);
2128 }
2129}
2130
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002131static int trace__add_syscall_newtp(struct trace *trace)
2132{
2133 int ret = -1;
2134 struct perf_evlist *evlist = trace->evlist;
2135 struct perf_evsel *sys_enter, *sys_exit;
2136
2137 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2138 if (sys_enter == NULL)
2139 goto out;
2140
2141 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2142 goto out_delete_sys_enter;
2143
2144 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2145 if (sys_exit == NULL)
2146 goto out_delete_sys_enter;
2147
2148 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2149 goto out_delete_sys_exit;
2150
2151 perf_evlist__add(evlist, sys_enter);
2152 perf_evlist__add(evlist, sys_exit);
2153
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002154 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002155 /*
2156 * We're interested only in the user space callchain
2157 * leading to the syscall, allow overriding that for
2158 * debugging reasons using --kernel_syscall_callchains
2159 */
2160 sys_exit->attr.exclude_callchain_kernel = 1;
2161 }
2162
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002163 trace->syscalls.events.sys_enter = sys_enter;
2164 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002165
2166 ret = 0;
2167out:
2168 return ret;
2169
2170out_delete_sys_exit:
2171 perf_evsel__delete_priv(sys_exit);
2172out_delete_sys_enter:
2173 perf_evsel__delete_priv(sys_enter);
2174 goto out;
2175}
2176
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002177static int trace__set_ev_qualifier_filter(struct trace *trace)
2178{
2179 int err = -1;
2180 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2181 trace->ev_qualifier_ids.nr,
2182 trace->ev_qualifier_ids.entries);
2183
2184 if (filter == NULL)
2185 goto out_enomem;
2186
2187 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2188 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2189
2190 free(filter);
2191out:
2192 return err;
2193out_enomem:
2194 errno = ENOMEM;
2195 goto out;
2196}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002197
Namhyung Kimf15eb532012-10-05 14:02:16 +09002198static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002199{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002200 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002201 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002202 int err = -1, i;
2203 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002204 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002205 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002206
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002207 trace->live = true;
2208
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002209 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002210 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002211
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002212 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002213 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002214
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002215 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2216 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2217 if (pgfault_maj == NULL)
2218 goto out_error_mem;
2219 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002220 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002221
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002222 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2223 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2224 if (pgfault_min == NULL)
2225 goto out_error_mem;
2226 perf_evlist__add(evlist, pgfault_min);
2227 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002228
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002229 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002230 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2231 trace__sched_stat_runtime))
2232 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002233
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002234 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2235 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002236 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002237 goto out_delete_evlist;
2238 }
2239
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002240 err = trace__symbols_init(trace, evlist);
2241 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002242 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002243 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002244 }
2245
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002246 perf_evlist__config(evlist, &trace->opts, NULL);
2247
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002248 if (callchain_param.enabled) {
2249 bool use_identifier = false;
2250
2251 if (trace->syscalls.events.sys_exit) {
2252 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2253 &trace->opts, &callchain_param);
2254 use_identifier = true;
2255 }
2256
2257 if (pgfault_maj) {
2258 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2259 use_identifier = true;
2260 }
2261
2262 if (pgfault_min) {
2263 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2264 use_identifier = true;
2265 }
2266
2267 if (use_identifier) {
2268 /*
2269 * Now we have evsels with different sample_ids, use
2270 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2271 * from a fixed position in each ring buffer record.
2272 *
2273 * As of this the changeset introducing this comment, this
2274 * isn't strictly needed, as the fields that can come before
2275 * PERF_SAMPLE_ID are all used, but we'll probably disable
2276 * some of those for things like copying the payload of
2277 * pointer syscall arguments, and for vfs_getname we don't
2278 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2279 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2280 */
2281 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2282 perf_evlist__reset_sample_bit(evlist, ID);
2283 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002284 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002285
Namhyung Kimf15eb532012-10-05 14:02:16 +09002286 signal(SIGCHLD, sig_handler);
2287 signal(SIGINT, sig_handler);
2288
2289 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002290 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002291 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002292 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002293 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002294 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002295 }
2296 }
2297
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002298 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002299 if (err < 0)
2300 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002301
Wang Nanba504232016-02-26 09:31:54 +00002302 err = bpf__apply_obj_config();
2303 if (err) {
2304 char errbuf[BUFSIZ];
2305
2306 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2307 pr_err("ERROR: Apply config to BPF failed: %s\n",
2308 errbuf);
2309 goto out_error_open;
2310 }
2311
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002312 /*
2313 * Better not use !target__has_task() here because we need to cover the
2314 * case where no threads were specified in the command line, but a
2315 * workload was, and in that case we will fill in the thread_map when
2316 * we fork the workload in perf_evlist__prepare_workload.
2317 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002318 if (trace->filter_pids.nr > 0)
2319 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002320 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002321 err = perf_evlist__set_filter_pid(evlist, getpid());
2322
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002323 if (err < 0)
2324 goto out_error_mem;
2325
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002326 if (trace->ev_qualifier_ids.nr > 0) {
2327 err = trace__set_ev_qualifier_filter(trace);
2328 if (err < 0)
2329 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002330
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002331 pr_debug("event qualifier tracepoint filter: %s\n",
2332 trace->syscalls.events.sys_exit->filter);
2333 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002334
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002335 err = perf_evlist__apply_filters(evlist, &evsel);
2336 if (err < 0)
2337 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002338
Jiri Olsaf8850372013-11-28 17:57:22 +01002339 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002340 if (err < 0)
2341 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002342
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002343 if (!target__none(&trace->opts.target))
2344 perf_evlist__enable(evlist);
2345
Namhyung Kimf15eb532012-10-05 14:02:16 +09002346 if (forks)
2347 perf_evlist__start_workload(evlist);
2348
Jiri Olsae13798c2015-06-23 00:36:02 +02002349 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002350 evlist->threads->nr > 1 ||
2351 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002352again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002353 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002354
2355 for (i = 0; i < evlist->nr_mmaps; i++) {
2356 union perf_event *event;
2357
2358 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002359 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002360
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002361 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002362
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002363 err = perf_evlist__parse_sample(evlist, event, &sample);
2364 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002365 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002366 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002367 }
2368
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002369 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002370next_event:
2371 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002372
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002373 if (interrupted)
2374 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002375
2376 if (done && !draining) {
2377 perf_evlist__disable(evlist);
2378 draining = true;
2379 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002380 }
2381 }
2382
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002383 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002384 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002385
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002386 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2387 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2388 draining = true;
2389
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002390 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002391 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002392 } else {
2393 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002394 }
2395
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002396out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002397 thread__zput(trace->current);
2398
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002399 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002400
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002401 if (!err) {
2402 if (trace->summary)
2403 trace__fprintf_thread_summary(trace, trace->output);
2404
2405 if (trace->show_tool_stats) {
2406 fprintf(trace->output, "Stats:\n "
2407 " vfs_getname : %" PRIu64 "\n"
2408 " proc_getname: %" PRIu64 "\n",
2409 trace->stats.vfs_getname,
2410 trace->stats.proc_getname);
2411 }
2412 }
David Ahernbf2575c2013-10-08 21:26:53 -06002413
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002414out_delete_evlist:
2415 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002416 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002417 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002418 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002419{
2420 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002421
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002422out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002423 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002424 goto out_error;
2425
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002426out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002427 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002428 goto out_error;
2429
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002430out_error_mmap:
2431 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2432 goto out_error;
2433
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002434out_error_open:
2435 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2436
2437out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002438 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302439 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002440
2441out_error_apply_filters:
2442 fprintf(trace->output,
2443 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2444 evsel->filter, perf_evsel__name(evsel), errno,
2445 strerror_r(errno, errbuf, sizeof(errbuf)));
2446 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002447}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002448out_error_mem:
2449 fprintf(trace->output, "Not enough memory to run!\n");
2450 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002451
2452out_errno:
2453 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2454 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002455}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002456
David Ahern6810fc92013-08-28 22:29:52 -06002457static int trace__replay(struct trace *trace)
2458{
2459 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002460 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002461 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002462 struct perf_data_file file = {
2463 .path = input_name,
2464 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002465 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002466 };
David Ahern6810fc92013-08-28 22:29:52 -06002467 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002468 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002469 int err = -1;
2470
2471 trace->tool.sample = trace__process_sample;
2472 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002473 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002474 trace->tool.comm = perf_event__process_comm;
2475 trace->tool.exit = perf_event__process_exit;
2476 trace->tool.fork = perf_event__process_fork;
2477 trace->tool.attr = perf_event__process_attr;
2478 trace->tool.tracing_data = perf_event__process_tracing_data;
2479 trace->tool.build_id = perf_event__process_build_id;
2480
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002481 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002482 trace->tool.ordering_requires_timestamps = true;
2483
2484 /* add tid to output */
2485 trace->multiple_threads = true;
2486
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002487 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002488 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002489 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002490
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002491 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002492 goto out;
2493
David Ahern8fb598e2013-09-28 13:13:00 -06002494 trace->host = &session->machines.host;
2495
David Ahern6810fc92013-08-28 22:29:52 -06002496 err = perf_session__set_tracepoints_handlers(session, handlers);
2497 if (err)
2498 goto out;
2499
Namhyung Kim003824e2013-11-12 15:25:00 +09002500 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2501 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002502 /* older kernels have syscalls tp versus raw_syscalls */
2503 if (evsel == NULL)
2504 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2505 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002506
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002507 if (evsel &&
2508 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2509 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002510 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2511 goto out;
2512 }
2513
2514 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2515 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002516 if (evsel == NULL)
2517 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2518 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002519 if (evsel &&
2520 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2521 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002522 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002523 goto out;
2524 }
2525
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002526 evlist__for_each(session->evlist, evsel) {
2527 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2528 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2529 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2530 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2531 evsel->handler = trace__pgfault;
2532 }
2533
David Ahernbdc89662013-08-28 22:29:53 -06002534 err = parse_target_str(trace);
2535 if (err != 0)
2536 goto out;
2537
David Ahern6810fc92013-08-28 22:29:52 -06002538 setup_pager();
2539
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002540 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002541 if (err)
2542 pr_err("Failed to process events, error %d", err);
2543
David Ahernbf2575c2013-10-08 21:26:53 -06002544 else if (trace->summary)
2545 trace__fprintf_thread_summary(trace, trace->output);
2546
David Ahern6810fc92013-08-28 22:29:52 -06002547out:
2548 perf_session__delete(session);
2549
2550 return err;
2551}
2552
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002553static size_t trace__fprintf_threads_header(FILE *fp)
2554{
2555 size_t printed;
2556
Pekka Enberg99ff7152013-11-12 16:42:14 +02002557 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002558
2559 return printed;
2560}
2561
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002562DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2563 struct stats *stats;
2564 double msecs;
2565 int syscall;
2566)
2567{
2568 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2569 struct stats *stats = source->priv;
2570
2571 entry->syscall = source->i;
2572 entry->stats = stats;
2573 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2574}
2575
David Ahernbf2575c2013-10-08 21:26:53 -06002576static size_t thread__dump_stats(struct thread_trace *ttrace,
2577 struct trace *trace, FILE *fp)
2578{
David Ahernbf2575c2013-10-08 21:26:53 -06002579 size_t printed = 0;
2580 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002581 struct rb_node *nd;
2582 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002583
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002584 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002585 return 0;
2586
2587 printed += fprintf(fp, "\n");
2588
Milian Wolff834fd462015-08-06 11:24:29 +02002589 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2590 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2591 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002592
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002593 resort_rb__for_each(nd, syscall_stats) {
2594 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002595 if (stats) {
2596 double min = (double)(stats->min) / NSEC_PER_MSEC;
2597 double max = (double)(stats->max) / NSEC_PER_MSEC;
2598 double avg = avg_stats(stats);
2599 double pct;
2600 u64 n = (u64) stats->n;
2601
2602 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2603 avg /= NSEC_PER_MSEC;
2604
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002605 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002606 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002607 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002608 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002609 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002610 }
David Ahernbf2575c2013-10-08 21:26:53 -06002611 }
2612
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002613 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002614 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002615
2616 return printed;
2617}
2618
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002619static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002620{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002621 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002622 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002623 double ratio;
2624
2625 if (ttrace == NULL)
2626 return 0;
2627
2628 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2629
Pekka Enberg15e65c62013-11-14 18:43:30 +02002630 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002631 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002632 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002633 if (ttrace->pfmaj)
2634 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2635 if (ttrace->pfmin)
2636 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002637 if (trace->sched)
2638 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2639 else if (fputc('\n', fp) != EOF)
2640 ++printed;
2641
David Ahernbf2575c2013-10-08 21:26:53 -06002642 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002643
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002644 return printed;
2645}
David Ahern896cbb52013-09-28 13:12:59 -06002646
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002647static unsigned long thread__nr_events(struct thread_trace *ttrace)
2648{
2649 return ttrace ? ttrace->nr_events : 0;
2650}
2651
2652DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2653 struct thread *thread;
2654)
2655{
2656 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002657}
2658
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002659static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2660{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002661 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2662 size_t printed = trace__fprintf_threads_header(fp);
2663 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002664
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002665 if (threads == NULL) {
2666 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2667 return 0;
2668 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002669
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002670 resort_rb__for_each(nd, threads)
2671 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2672
2673 resort_rb__delete(threads);
2674
2675 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002676}
2677
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002678static int trace__set_duration(const struct option *opt, const char *str,
2679 int unset __maybe_unused)
2680{
2681 struct trace *trace = opt->value;
2682
2683 trace->duration_filter = atof(str);
2684 return 0;
2685}
2686
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002687static int trace__set_filter_pids(const struct option *opt, const char *str,
2688 int unset __maybe_unused)
2689{
2690 int ret = -1;
2691 size_t i;
2692 struct trace *trace = opt->value;
2693 /*
2694 * FIXME: introduce a intarray class, plain parse csv and create a
2695 * { int nr, int entries[] } struct...
2696 */
2697 struct intlist *list = intlist__new(str);
2698
2699 if (list == NULL)
2700 return -1;
2701
2702 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2703 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2704
2705 if (trace->filter_pids.entries == NULL)
2706 goto out;
2707
2708 trace->filter_pids.entries[0] = getpid();
2709
2710 for (i = 1; i < trace->filter_pids.nr; ++i)
2711 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2712
2713 intlist__delete(list);
2714 ret = 0;
2715out:
2716 return ret;
2717}
2718
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002719static int trace__open_output(struct trace *trace, const char *filename)
2720{
2721 struct stat st;
2722
2723 if (!stat(filename, &st) && st.st_size) {
2724 char oldname[PATH_MAX];
2725
2726 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2727 unlink(oldname);
2728 rename(filename, oldname);
2729 }
2730
2731 trace->output = fopen(filename, "w");
2732
2733 return trace->output == NULL ? -errno : 0;
2734}
2735
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002736static int parse_pagefaults(const struct option *opt, const char *str,
2737 int unset __maybe_unused)
2738{
2739 int *trace_pgfaults = opt->value;
2740
2741 if (strcmp(str, "all") == 0)
2742 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2743 else if (strcmp(str, "maj") == 0)
2744 *trace_pgfaults |= TRACE_PFMAJ;
2745 else if (strcmp(str, "min") == 0)
2746 *trace_pgfaults |= TRACE_PFMIN;
2747 else
2748 return -1;
2749
2750 return 0;
2751}
2752
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002753static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2754{
2755 struct perf_evsel *evsel;
2756
2757 evlist__for_each(evlist, evsel)
2758 evsel->handler = handler;
2759}
2760
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002761int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2762{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002763 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002764 "perf trace [<options>] [<command>]",
2765 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002766 "perf trace record [<options>] [<command>]",
2767 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002768 NULL
2769 };
2770 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002771 .syscalls = {
2772 . max = -1,
2773 },
2774 .opts = {
2775 .target = {
2776 .uid = UINT_MAX,
2777 .uses_mmap = true,
2778 },
2779 .user_freq = UINT_MAX,
2780 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002781 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002782 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002783 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002784 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002785 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002786 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002787 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002788 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002789 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002790 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002791 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002792 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002793 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002794 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2795 "event selector. use 'perf list' to list available events",
2796 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002797 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2798 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002799 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002800 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002801 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002802 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002803 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2804 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002805 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002806 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002807 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2808 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002809 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002810 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002811 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002812 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002813 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002814 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002815 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2816 "number of mmap data pages",
2817 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002818 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002819 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002820 OPT_CALLBACK(0, "duration", &trace, "float",
2821 "show only events with duration > N.M ms",
2822 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002823 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002824 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002825 OPT_BOOLEAN('T', "time", &trace.full_time,
2826 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002827 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2828 "Show only syscall summary with statistics"),
2829 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2830 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002831 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2832 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002833 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002834 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002835 OPT_CALLBACK(0, "call-graph", &trace.opts,
2836 "record_mode[,record_size]", record_callchain_help,
2837 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002838 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2839 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002840 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2841 "Set the minimum stack depth when parsing the callchain, "
2842 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002843 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2844 "Set the maximum stack depth when parsing the callchain, "
2845 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002846 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002847 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2848 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002849 OPT_END()
2850 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002851 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002852 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002853 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002854 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002855 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002856
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002857 signal(SIGSEGV, sighandler_dump_stack);
2858 signal(SIGFPE, sighandler_dump_stack);
2859
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002860 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002861 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002862
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002863 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002864 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002865 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002866 goto out;
2867 }
2868
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002869 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2870 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002871
Wang Nand7888572016-04-08 15:07:24 +00002872 err = bpf__setup_stdout(trace.evlist);
2873 if (err) {
2874 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2875 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2876 goto out;
2877 }
2878
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002879 err = -1;
2880
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002881 if (trace.trace_pgfaults) {
2882 trace.opts.sample_address = true;
2883 trace.opts.sample_time = true;
2884 }
2885
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002886 if (trace.opts.mmap_pages == UINT_MAX)
2887 mmap_pages_user_set = false;
2888
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002889 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002890 trace.max_stack = sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002891 max_stack_user_set = false;
2892 }
2893
2894#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002895 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002896 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2897#endif
2898
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002899 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002900 if (!mmap_pages_user_set && geteuid() == 0)
2901 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2902
Milian Wolff566a0882016-04-08 13:34:15 +02002903 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002904 }
Milian Wolff566a0882016-04-08 13:34:15 +02002905
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002906 if (trace.evlist->nr_entries > 0)
2907 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2908
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002909 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2910 return trace__record(&trace, argc-1, &argv[1]);
2911
2912 /* summary_only implies summary option, but don't overwrite summary if set */
2913 if (trace.summary_only)
2914 trace.summary = trace.summary_only;
2915
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002916 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2917 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002918 pr_err("Please specify something to trace.\n");
2919 return -1;
2920 }
2921
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002922 if (!trace.trace_syscalls && ev_qualifier_str) {
2923 pr_err("The -e option can't be used with --no-syscalls.\n");
2924 goto out;
2925 }
2926
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002927 if (output_name != NULL) {
2928 err = trace__open_output(&trace, output_name);
2929 if (err < 0) {
2930 perror("failed to create output file");
2931 goto out;
2932 }
2933 }
2934
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002935 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2936
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002937 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002938 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002939 struct strlist_config slist_config = {
2940 .dirname = system_path(STRACE_GROUPS_DIR),
2941 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002942
2943 trace.not_ev_qualifier = *s == '!';
2944 if (trace.not_ev_qualifier)
2945 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002946 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002947 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002948 fputs("Not enough memory to parse event qualifier",
2949 trace.output);
2950 err = -ENOMEM;
2951 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002952 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002953
2954 err = trace__validate_ev_qualifier(&trace);
2955 if (err)
2956 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002957 }
2958
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002959 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002960 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002961 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002962 fprintf(trace.output, "%s", bf);
2963 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002964 }
2965
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002966 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002967 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002968 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002969 fprintf(trace.output, "%s", bf);
2970 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002971 }
2972
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002973 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002974 trace.opts.target.system_wide = true;
2975
David Ahern6810fc92013-08-28 22:29:52 -06002976 if (input_name)
2977 err = trace__replay(&trace);
2978 else
2979 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002980
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002981out_close:
2982 if (output_name != NULL)
2983 fclose(trace.output);
2984out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002985 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002986}