blob: 7401de71d0974f53e923a42d85514046bd702d75 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/filter.h>
45#include <linux/audit.h>
46#include <sys/ptrace.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030047#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030048#include <linux/stringify.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030049
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030050#ifndef O_CLOEXEC
51# define O_CLOEXEC 02000000
52#endif
53
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030054struct trace {
55 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030056 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030057 struct {
58 int max;
59 struct syscall *table;
60 struct {
61 struct perf_evsel *sys_enter,
62 *sys_exit;
63 } events;
64 } syscalls;
65 struct record_opts opts;
66 struct perf_evlist *evlist;
67 struct machine *host;
68 struct thread *current;
69 u64 base_time;
70 FILE *output;
71 unsigned long nr_events;
72 struct strlist *ev_qualifier;
73 struct {
74 size_t nr;
75 int *entries;
76 } ev_qualifier_ids;
77 struct intlist *tid_list;
78 struct intlist *pid_list;
79 struct {
80 size_t nr;
81 pid_t *entries;
82 } filter_pids;
83 double duration_filter;
84 double runtime_ms;
85 struct {
86 u64 vfs_getname,
87 proc_getname;
88 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030089 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030090 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030091 bool not_ev_qualifier;
92 bool live;
93 bool full_time;
94 bool sched;
95 bool multiple_threads;
96 bool summary;
97 bool summary_only;
98 bool show_comm;
99 bool show_tool_stats;
100 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300101 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300102 bool force;
103 bool vfs_getname;
104 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300105 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300107
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300108struct tp_field {
109 int offset;
110 union {
111 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
112 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
113 };
114};
115
116#define TP_UINT_FIELD(bits) \
117static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
118{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500119 u##bits value; \
120 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
121 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300122}
123
124TP_UINT_FIELD(8);
125TP_UINT_FIELD(16);
126TP_UINT_FIELD(32);
127TP_UINT_FIELD(64);
128
129#define TP_UINT_FIELD__SWAPPED(bits) \
130static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
131{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500132 u##bits value; \
133 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300134 return bswap_##bits(value);\
135}
136
137TP_UINT_FIELD__SWAPPED(16);
138TP_UINT_FIELD__SWAPPED(32);
139TP_UINT_FIELD__SWAPPED(64);
140
141static int tp_field__init_uint(struct tp_field *field,
142 struct format_field *format_field,
143 bool needs_swap)
144{
145 field->offset = format_field->offset;
146
147 switch (format_field->size) {
148 case 1:
149 field->integer = tp_field__u8;
150 break;
151 case 2:
152 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
153 break;
154 case 4:
155 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
156 break;
157 case 8:
158 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
159 break;
160 default:
161 return -1;
162 }
163
164 return 0;
165}
166
167static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
168{
169 return sample->raw_data + field->offset;
170}
171
172static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
173{
174 field->offset = format_field->offset;
175 field->pointer = tp_field__ptr;
176 return 0;
177}
178
179struct syscall_tp {
180 struct tp_field id;
181 union {
182 struct tp_field args, ret;
183 };
184};
185
186static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
187 struct tp_field *field,
188 const char *name)
189{
190 struct format_field *format_field = perf_evsel__field(evsel, name);
191
192 if (format_field == NULL)
193 return -1;
194
195 return tp_field__init_uint(field, format_field, evsel->needs_swap);
196}
197
198#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
199 ({ struct syscall_tp *sc = evsel->priv;\
200 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
201
202static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
203 struct tp_field *field,
204 const char *name)
205{
206 struct format_field *format_field = perf_evsel__field(evsel, name);
207
208 if (format_field == NULL)
209 return -1;
210
211 return tp_field__init_ptr(field, format_field);
212}
213
214#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
215 ({ struct syscall_tp *sc = evsel->priv;\
216 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
217
218static void perf_evsel__delete_priv(struct perf_evsel *evsel)
219{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300220 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300221 perf_evsel__delete(evsel);
222}
223
Namhyung Kim96695d42013-11-12 08:51:45 -0300224static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
225{
226 evsel->priv = malloc(sizeof(struct syscall_tp));
227 if (evsel->priv != NULL) {
228 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
229 goto out_delete;
230
231 evsel->handler = handler;
232 return 0;
233 }
234
235 return -ENOMEM;
236
237out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300238 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300239 return -ENOENT;
240}
241
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300242static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300243{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245
David Ahern9aca7f12013-12-04 19:41:39 -0700246 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200247 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700248 evsel = perf_evsel__newtp("syscalls", direction);
249
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200250 if (IS_ERR(evsel))
251 return NULL;
252
253 if (perf_evsel__init_syscall_tp(evsel, handler))
254 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300255
256 return evsel;
257
258out_delete:
259 perf_evsel__delete_priv(evsel);
260 return NULL;
261}
262
263#define perf_evsel__sc_tp_uint(evsel, name, sample) \
264 ({ struct syscall_tp *fields = evsel->priv; \
265 fields->name.integer(&fields->name, sample); })
266
267#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
268 ({ struct syscall_tp *fields = evsel->priv; \
269 fields->name.pointer(&fields->name, sample); })
270
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271struct syscall_arg {
272 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300273 struct thread *thread;
274 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300275 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300276 u8 idx;
277 u8 mask;
278};
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300281 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282 int nr_entries;
283 const char **entries;
284};
285
286#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
287 .nr_entries = ARRAY_SIZE(array), \
288 .entries = array, \
289}
290
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300291#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
292 .offset = off, \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300297static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
298 const char *intfmt,
299 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300302 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303
304 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300305 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306
307 return scnprintf(bf, size, "%s", sa->entries[idx]);
308}
309
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300310static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
311 struct syscall_arg *arg)
312{
313 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
314}
315
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316#define SCA_STRARRAY syscall_arg__scnprintf_strarray
317
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300318#if defined(__i386__) || defined(__x86_64__)
319/*
320 * FIXME: Make this available to all arches as soon as the ioctl beautifier
321 * gets rewritten to support all arches.
322 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300323static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
324 struct syscall_arg *arg)
325{
326 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
327}
328
329#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300330#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300331
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300332static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
333 struct syscall_arg *arg);
334
335#define SCA_FD syscall_arg__scnprintf_fd
336
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
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001163static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1164{
1165 struct machine *machine = vmachine;
1166
1167 if (machine->kptr_restrict_warned)
1168 return NULL;
1169
1170 if (symbol_conf.kptr_restrict) {
1171 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1172 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1173 "Kernel samples will not be resolved.\n");
1174 machine->kptr_restrict_warned = true;
1175 return NULL;
1176 }
1177
1178 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1179}
1180
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001181static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1182{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001183 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001184
1185 if (err)
1186 return err;
1187
David Ahern8fb598e2013-09-28 13:13:00 -06001188 trace->host = machine__new_host();
1189 if (trace->host == NULL)
1190 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001191
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001192 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001193 return -errno;
1194
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001195 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001196 evlist->threads, trace__tool_process, false,
1197 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001198 if (err)
1199 symbol__exit();
1200
1201 return err;
1202}
1203
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001204static int syscall__set_arg_fmts(struct syscall *sc)
1205{
1206 struct format_field *field;
1207 int idx = 0;
1208
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001209 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001210 if (sc->arg_scnprintf == NULL)
1211 return -1;
1212
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001213 if (sc->fmt)
1214 sc->arg_parm = sc->fmt->arg_parm;
1215
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001216 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001217 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1218 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1219 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001220 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001221 else if (strcmp(field->type, "pid_t") == 0)
1222 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001223 else if (strcmp(field->type, "umode_t") == 0)
1224 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001225 ++idx;
1226 }
1227
1228 return 0;
1229}
1230
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001231static int trace__read_syscall_info(struct trace *trace, int id)
1232{
1233 char tp_name[128];
1234 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001235 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001236
1237 if (name == NULL)
1238 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001239
1240 if (id > trace->syscalls.max) {
1241 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1242
1243 if (nsyscalls == NULL)
1244 return -1;
1245
1246 if (trace->syscalls.max != -1) {
1247 memset(nsyscalls + trace->syscalls.max + 1, 0,
1248 (id - trace->syscalls.max) * sizeof(*sc));
1249 } else {
1250 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1251 }
1252
1253 trace->syscalls.table = nsyscalls;
1254 trace->syscalls.max = id;
1255 }
1256
1257 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001258 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001259
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001260 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001261
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001262 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001263 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001264
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001265 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001266 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001267 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001268 }
1269
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001270 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001271 return -1;
1272
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001273 sc->args = sc->tp_format->format.fields;
1274 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001275 /*
1276 * We need to check and discard the first variable '__syscall_nr'
1277 * or 'nr' that mean the syscall number. It is needless here.
1278 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1279 */
1280 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001281 sc->args = sc->args->next;
1282 --sc->nr_args;
1283 }
1284
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001285 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1286
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001287 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001288}
1289
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001290static int trace__validate_ev_qualifier(struct trace *trace)
1291{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001292 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001293 struct str_node *pos;
1294
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001295 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1296 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1297 sizeof(trace->ev_qualifier_ids.entries[0]));
1298
1299 if (trace->ev_qualifier_ids.entries == NULL) {
1300 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1301 trace->output);
1302 err = -EINVAL;
1303 goto out;
1304 }
1305
1306 i = 0;
1307
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001308 strlist__for_each(pos, trace->ev_qualifier) {
1309 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001310 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001311
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001312 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001313 if (err == 0) {
1314 fputs("Error:\tInvalid syscall ", trace->output);
1315 err = -EINVAL;
1316 } else {
1317 fputs(", ", trace->output);
1318 }
1319
1320 fputs(sc, trace->output);
1321 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001322
1323 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001324 }
1325
1326 if (err < 0) {
1327 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1328 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001329 zfree(&trace->ev_qualifier_ids.entries);
1330 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001331 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001332out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001333 return err;
1334}
1335
David Ahern55d43bc2015-02-19 15:00:22 -05001336/*
1337 * args is to be interpreted as a series of longs but we need to handle
1338 * 8-byte unaligned accesses. args points to raw_data within the event
1339 * and raw_data is guaranteed to be 8-byte unaligned because it is
1340 * preceded by raw_size which is a u32. So we need to copy args to a temp
1341 * variable to read it. Most notably this avoids extended load instructions
1342 * on unaligned addresses
1343 */
1344
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001345static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001346 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001347 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001348{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001349 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001350 unsigned char *p;
1351 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001352
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001353 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001354 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001355 u8 bit = 1;
1356 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001357 .idx = 0,
1358 .mask = 0,
1359 .trace = trace,
1360 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001361 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001362
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001363 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001364 field = field->next, ++arg.idx, bit <<= 1) {
1365 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001366 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001367
1368 /* special care for unaligned accesses */
1369 p = args + sizeof(unsigned long) * arg.idx;
1370 memcpy(&val, p, sizeof(val));
1371
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001372 /*
1373 * Suppress this argument if its value is zero and
1374 * and we don't have a string associated in an
1375 * strarray for it.
1376 */
David Ahern55d43bc2015-02-19 15:00:22 -05001377 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001378 !(sc->arg_scnprintf &&
1379 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1380 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001381 continue;
1382
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001383 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001384 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001385 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001386 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001387 if (sc->arg_parm)
1388 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001389 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1390 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001391 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001392 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001393 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001394 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001395 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001396 } else if (IS_ERR(sc->tp_format)) {
1397 /*
1398 * If we managed to read the tracepoint /format file, then we
1399 * may end up not having any args, like with gettid(), so only
1400 * print the raw args when we didn't manage to read it.
1401 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001402 int i = 0;
1403
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001404 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001405 /* special care for unaligned accesses */
1406 p = args + sizeof(unsigned long) * i;
1407 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001408 printed += scnprintf(bf + printed, size - printed,
1409 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001410 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001411 ++i;
1412 }
1413 }
1414
1415 return printed;
1416}
1417
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001418typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001419 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001420 struct perf_sample *sample);
1421
1422static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001423 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001424{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001425
1426 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001427
1428 /*
1429 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1430 * before that, leaving at a higher verbosity level till that is
1431 * explained. Reproduced with plain ftrace with:
1432 *
1433 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1434 * grep "NR -1 " /t/trace_pipe
1435 *
1436 * After generating some load on the machine.
1437 */
1438 if (verbose > 1) {
1439 static u64 n;
1440 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1441 id, perf_evsel__name(evsel), ++n);
1442 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001443 return NULL;
1444 }
1445
1446 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1447 trace__read_syscall_info(trace, id))
1448 goto out_cant_read;
1449
1450 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1451 goto out_cant_read;
1452
1453 return &trace->syscalls.table[id];
1454
1455out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001456 if (verbose) {
1457 fprintf(trace->output, "Problems reading syscall %d", id);
1458 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1459 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1460 fputs(" information\n", trace->output);
1461 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001462 return NULL;
1463}
1464
David Ahernbf2575c2013-10-08 21:26:53 -06001465static void thread__update_stats(struct thread_trace *ttrace,
1466 int id, struct perf_sample *sample)
1467{
1468 struct int_node *inode;
1469 struct stats *stats;
1470 u64 duration = 0;
1471
1472 inode = intlist__findnew(ttrace->syscall_stats, id);
1473 if (inode == NULL)
1474 return;
1475
1476 stats = inode->priv;
1477 if (stats == NULL) {
1478 stats = malloc(sizeof(struct stats));
1479 if (stats == NULL)
1480 return;
1481 init_stats(stats);
1482 inode->priv = stats;
1483 }
1484
1485 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1486 duration = sample->time - ttrace->entry_time;
1487
1488 update_stats(stats, duration);
1489}
1490
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001491static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1492{
1493 struct thread_trace *ttrace;
1494 u64 duration;
1495 size_t printed;
1496
1497 if (trace->current == NULL)
1498 return 0;
1499
1500 ttrace = thread__priv(trace->current);
1501
1502 if (!ttrace->entry_pending)
1503 return 0;
1504
1505 duration = sample->time - ttrace->entry_time;
1506
1507 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1508 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1509 ttrace->entry_pending = false;
1510
1511 return printed;
1512}
1513
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001514static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001515 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001516 struct perf_sample *sample)
1517{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001518 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001519 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001521 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001522 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001523 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001524 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001525
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001526 if (sc == NULL)
1527 return -1;
1528
David Ahern8fb598e2013-09-28 13:13:00 -06001529 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001530 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001531 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001532 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001533
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001534 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001535
1536 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001537 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001538 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001539 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001540 }
1541
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001542 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001543 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001544
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001545 ttrace->entry_time = sample->time;
1546 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001547 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001548
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001549 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001550 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001551
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001552 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001553 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001554 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001555 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001556 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001557 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001558 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001559 /* See trace__vfs_getname & trace__sys_exit */
1560 ttrace->filename.pending_open = false;
1561 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001562
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001563 if (trace->current != thread) {
1564 thread__put(trace->current);
1565 trace->current = thread__get(thread);
1566 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001567 err = 0;
1568out_put:
1569 thread__put(thread);
1570 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001571}
1572
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001573static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1574 struct perf_sample *sample,
1575 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001576{
1577 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001578
1579 if (machine__resolve(trace->host, &al, sample) < 0 ||
1580 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1581 return -1;
1582
1583 return 0;
1584}
1585
1586static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1587{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001588 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001589 const unsigned int print_opts = EVSEL__PRINT_SYM |
1590 EVSEL__PRINT_DSO |
1591 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001592
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001593 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001594}
1595
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001596static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001597 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001598 struct perf_sample *sample)
1599{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001600 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001601 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001602 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001603 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001604 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001605 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001606
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001607 if (sc == NULL)
1608 return -1;
1609
David Ahern8fb598e2013-09-28 13:13:00 -06001610 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001611 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001612 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001613 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001614
David Ahernbf2575c2013-10-08 21:26:53 -06001615 if (trace->summary)
1616 thread__update_stats(ttrace, id, sample);
1617
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001618 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001619
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001620 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001621 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1622 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001623 ++trace->stats.vfs_getname;
1624 }
1625
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001626 ttrace->exit_time = sample->time;
1627
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001628 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001629 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001630 if (trace__filter_duration(trace, duration))
1631 goto out;
1632 } else if (trace->duration_filter)
1633 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001634
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001635 if (sample->callchain) {
1636 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1637 if (callchain_ret == 0) {
1638 if (callchain_cursor.nr < trace->min_stack)
1639 goto out;
1640 callchain_ret = 1;
1641 }
1642 }
1643
David Ahernfd2eaba2013-11-12 09:31:15 -07001644 if (trace->summary_only)
1645 goto out;
1646
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001647 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001648
1649 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001650 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001651 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001652 fprintf(trace->output, " ... [");
1653 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1654 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001655 }
1656
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001657 if (sc->fmt == NULL) {
1658signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001659 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001660 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001661 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001662 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1663 *e = audit_errno_to_name(-ret);
1664
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001665 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001666 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001667 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001668 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001669 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001670 else if (sc->fmt->errpid) {
1671 struct thread *child = machine__find_thread(trace->host, ret, ret);
1672
1673 if (child != NULL) {
1674 fprintf(trace->output, ") = %ld", ret);
1675 if (child->comm_set)
1676 fprintf(trace->output, " (%s)", thread__comm_str(child));
1677 thread__put(child);
1678 }
1679 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001680 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001681
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001682 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001683
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001684 if (callchain_ret > 0)
1685 trace__fprintf_callchain(trace, sample);
1686 else if (callchain_ret < 0)
1687 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001688out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001689 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001690 err = 0;
1691out_put:
1692 thread__put(thread);
1693 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001694}
1695
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001696static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001697 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001698 struct perf_sample *sample)
1699{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001700 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1701 struct thread_trace *ttrace;
1702 size_t filename_len, entry_str_len, to_move;
1703 ssize_t remaining_space;
1704 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001705 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001706
1707 if (!thread)
1708 goto out;
1709
1710 ttrace = thread__priv(thread);
1711 if (!ttrace)
1712 goto out;
1713
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001714 filename_len = strlen(filename);
1715
1716 if (ttrace->filename.namelen < filename_len) {
1717 char *f = realloc(ttrace->filename.name, filename_len + 1);
1718
1719 if (f == NULL)
1720 goto out;
1721
1722 ttrace->filename.namelen = filename_len;
1723 ttrace->filename.name = f;
1724 }
1725
1726 strcpy(ttrace->filename.name, filename);
1727 ttrace->filename.pending_open = true;
1728
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001729 if (!ttrace->filename.ptr)
1730 goto out;
1731
1732 entry_str_len = strlen(ttrace->entry_str);
1733 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1734 if (remaining_space <= 0)
1735 goto out;
1736
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001737 if (filename_len > (size_t)remaining_space) {
1738 filename += filename_len - remaining_space;
1739 filename_len = remaining_space;
1740 }
1741
1742 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1743 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1744 memmove(pos + filename_len, pos, to_move);
1745 memcpy(pos, filename, filename_len);
1746
1747 ttrace->filename.ptr = 0;
1748 ttrace->filename.entry_str_pos = 0;
1749out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001750 return 0;
1751}
1752
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001753static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001754 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001755 struct perf_sample *sample)
1756{
1757 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1758 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001759 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001760 sample->pid,
1761 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001762 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001763
1764 if (ttrace == NULL)
1765 goto out_dump;
1766
1767 ttrace->runtime_ms += runtime_ms;
1768 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001769 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001770 return 0;
1771
1772out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001773 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001774 evsel->name,
1775 perf_evsel__strval(evsel, sample, "comm"),
1776 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1777 runtime,
1778 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001779 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001780 return 0;
1781}
1782
Wang Nan1d6c9402016-02-26 09:31:55 +00001783static void bpf_output__printer(enum binary_printer_ops op,
1784 unsigned int val, void *extra)
1785{
1786 FILE *output = extra;
1787 unsigned char ch = (unsigned char)val;
1788
1789 switch (op) {
1790 case BINARY_PRINT_CHAR_DATA:
1791 fprintf(output, "%c", isprint(ch) ? ch : '.');
1792 break;
1793 case BINARY_PRINT_DATA_BEGIN:
1794 case BINARY_PRINT_LINE_BEGIN:
1795 case BINARY_PRINT_ADDR:
1796 case BINARY_PRINT_NUM_DATA:
1797 case BINARY_PRINT_NUM_PAD:
1798 case BINARY_PRINT_SEP:
1799 case BINARY_PRINT_CHAR_PAD:
1800 case BINARY_PRINT_LINE_END:
1801 case BINARY_PRINT_DATA_END:
1802 default:
1803 break;
1804 }
1805}
1806
1807static void bpf_output__fprintf(struct trace *trace,
1808 struct perf_sample *sample)
1809{
1810 print_binary(sample->raw_data, sample->raw_size, 8,
1811 bpf_output__printer, trace->output);
1812}
1813
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001814static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1815 union perf_event *event __maybe_unused,
1816 struct perf_sample *sample)
1817{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001818 int callchain_ret = 0;
1819
1820 if (sample->callchain) {
1821 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1822 if (callchain_ret == 0) {
1823 if (callchain_cursor.nr < trace->min_stack)
1824 goto out;
1825 callchain_ret = 1;
1826 }
1827 }
1828
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001829 trace__printf_interrupted_entry(trace, sample);
1830 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001831
1832 if (trace->trace_syscalls)
1833 fprintf(trace->output, "( ): ");
1834
1835 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001836
Wang Nan1d6c9402016-02-26 09:31:55 +00001837 if (perf_evsel__is_bpf_output(evsel)) {
1838 bpf_output__fprintf(trace, sample);
1839 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001840 event_format__fprintf(evsel->tp_format, sample->cpu,
1841 sample->raw_data, sample->raw_size,
1842 trace->output);
1843 }
1844
1845 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001846
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001847 if (callchain_ret > 0)
1848 trace__fprintf_callchain(trace, sample);
1849 else if (callchain_ret < 0)
1850 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1851out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001852 return 0;
1853}
1854
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001855static void print_location(FILE *f, struct perf_sample *sample,
1856 struct addr_location *al,
1857 bool print_dso, bool print_sym)
1858{
1859
1860 if ((verbose || print_dso) && al->map)
1861 fprintf(f, "%s@", al->map->dso->long_name);
1862
1863 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001864 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001865 al->addr - al->sym->start);
1866 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001867 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001868 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001869 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001870}
1871
1872static int trace__pgfault(struct trace *trace,
1873 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001874 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001875 struct perf_sample *sample)
1876{
1877 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001878 struct addr_location al;
1879 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001880 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001881 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001882 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001883
1884 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001885
1886 if (sample->callchain) {
1887 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1888 if (callchain_ret == 0) {
1889 if (callchain_cursor.nr < trace->min_stack)
1890 goto out_put;
1891 callchain_ret = 1;
1892 }
1893 }
1894
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001895 ttrace = thread__trace(thread, trace->output);
1896 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001897 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001898
1899 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1900 ttrace->pfmaj++;
1901 else
1902 ttrace->pfmin++;
1903
1904 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001905 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001906
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001907 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001908 sample->ip, &al);
1909
1910 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
1911
1912 fprintf(trace->output, "%sfault [",
1913 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1914 "maj" : "min");
1915
1916 print_location(trace->output, sample, &al, false, true);
1917
1918 fprintf(trace->output, "] => ");
1919
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001920 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001921 sample->addr, &al);
1922
1923 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001924 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001925 MAP__FUNCTION, sample->addr, &al);
1926
1927 if (al.map)
1928 map_type = 'x';
1929 else
1930 map_type = '?';
1931 }
1932
1933 print_location(trace->output, sample, &al, true, false);
1934
1935 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001936
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001937 if (callchain_ret > 0)
1938 trace__fprintf_callchain(trace, sample);
1939 else if (callchain_ret < 0)
1940 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001941out:
1942 err = 0;
1943out_put:
1944 thread__put(thread);
1945 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001946}
1947
David Ahernbdc89662013-08-28 22:29:53 -06001948static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1949{
1950 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1951 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1952 return false;
1953
1954 if (trace->pid_list || trace->tid_list)
1955 return true;
1956
1957 return false;
1958}
1959
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001960static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001961 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001962 struct perf_sample *sample)
1963{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001964 /*
1965 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1966 * and don't use sample->time unconditionally, we may end up having
1967 * some other event in the future without PERF_SAMPLE_TIME for good
1968 * reason, i.e. we may not be interested in its timestamps, just in
1969 * it taking place, picking some piece of information when it
1970 * appears in our event stream (vfs_getname comes to mind).
1971 */
1972 if (trace->base_time == 0 && !trace->full_time &&
1973 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001974 trace->base_time = sample->time;
1975}
1976
David Ahern6810fc92013-08-28 22:29:52 -06001977static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001978 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001979 struct perf_sample *sample,
1980 struct perf_evsel *evsel,
1981 struct machine *machine __maybe_unused)
1982{
1983 struct trace *trace = container_of(tool, struct trace, tool);
1984 int err = 0;
1985
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001986 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001987
David Ahernbdc89662013-08-28 22:29:53 -06001988 if (skip_sample(trace, sample))
1989 return 0;
1990
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001991 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001992
David Ahern31605652013-12-04 19:41:41 -07001993 if (handler) {
1994 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001995 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001996 }
David Ahern6810fc92013-08-28 22:29:52 -06001997
1998 return err;
1999}
2000
David Ahernbdc89662013-08-28 22:29:53 -06002001static int parse_target_str(struct trace *trace)
2002{
2003 if (trace->opts.target.pid) {
2004 trace->pid_list = intlist__new(trace->opts.target.pid);
2005 if (trace->pid_list == NULL) {
2006 pr_err("Error parsing process id string\n");
2007 return -EINVAL;
2008 }
2009 }
2010
2011 if (trace->opts.target.tid) {
2012 trace->tid_list = intlist__new(trace->opts.target.tid);
2013 if (trace->tid_list == NULL) {
2014 pr_err("Error parsing thread id string\n");
2015 return -EINVAL;
2016 }
2017 }
2018
2019 return 0;
2020}
2021
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002022static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002023{
2024 unsigned int rec_argc, i, j;
2025 const char **rec_argv;
2026 const char * const record_args[] = {
2027 "record",
2028 "-R",
2029 "-m", "1024",
2030 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002031 };
2032
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002033 const char * const sc_args[] = { "-e", };
2034 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2035 const char * const majpf_args[] = { "-e", "major-faults" };
2036 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2037 const char * const minpf_args[] = { "-e", "minor-faults" };
2038 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2039
David Ahern9aca7f12013-12-04 19:41:39 -07002040 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002041 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2042 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002043 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2044
2045 if (rec_argv == NULL)
2046 return -ENOMEM;
2047
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002048 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002049 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002050 rec_argv[j++] = record_args[i];
2051
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002052 if (trace->trace_syscalls) {
2053 for (i = 0; i < sc_args_nr; i++)
2054 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002055
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002056 /* event string may be different for older kernels - e.g., RHEL6 */
2057 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2058 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2059 else if (is_valid_tracepoint("syscalls:sys_enter"))
2060 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2061 else {
2062 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2063 return -1;
2064 }
David Ahern9aca7f12013-12-04 19:41:39 -07002065 }
David Ahern9aca7f12013-12-04 19:41:39 -07002066
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002067 if (trace->trace_pgfaults & TRACE_PFMAJ)
2068 for (i = 0; i < majpf_args_nr; i++)
2069 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002070
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002071 if (trace->trace_pgfaults & TRACE_PFMIN)
2072 for (i = 0; i < minpf_args_nr; i++)
2073 rec_argv[j++] = minpf_args[i];
2074
2075 for (i = 0; i < (unsigned int)argc; i++)
2076 rec_argv[j++] = argv[i];
2077
2078 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002079}
2080
David Ahernbf2575c2013-10-08 21:26:53 -06002081static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2082
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002083static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002084{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002085 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002086
2087 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002088 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002089
2090 if (perf_evsel__field(evsel, "pathname") == NULL) {
2091 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002092 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002093 }
2094
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002095 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002096 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002097 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002098}
2099
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002100static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002101{
2102 struct perf_evsel *evsel;
2103 struct perf_event_attr attr = {
2104 .type = PERF_TYPE_SOFTWARE,
2105 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002106 };
2107
2108 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002109 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002110
2111 event_attr_init(&attr);
2112
2113 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002114 if (evsel)
2115 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002116
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002117 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002118}
2119
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002120static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2121{
2122 const u32 type = event->header.type;
2123 struct perf_evsel *evsel;
2124
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002125 if (type != PERF_RECORD_SAMPLE) {
2126 trace__process_event(trace, trace->host, event, sample);
2127 return;
2128 }
2129
2130 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2131 if (evsel == NULL) {
2132 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2133 return;
2134 }
2135
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002136 trace__set_base_time(trace, evsel, sample);
2137
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002138 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2139 sample->raw_data == NULL) {
2140 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2141 perf_evsel__name(evsel), sample->tid,
2142 sample->cpu, sample->raw_size);
2143 } else {
2144 tracepoint_handler handler = evsel->handler;
2145 handler(trace, evsel, event, sample);
2146 }
2147}
2148
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002149static int trace__add_syscall_newtp(struct trace *trace)
2150{
2151 int ret = -1;
2152 struct perf_evlist *evlist = trace->evlist;
2153 struct perf_evsel *sys_enter, *sys_exit;
2154
2155 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2156 if (sys_enter == NULL)
2157 goto out;
2158
2159 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2160 goto out_delete_sys_enter;
2161
2162 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2163 if (sys_exit == NULL)
2164 goto out_delete_sys_enter;
2165
2166 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2167 goto out_delete_sys_exit;
2168
2169 perf_evlist__add(evlist, sys_enter);
2170 perf_evlist__add(evlist, sys_exit);
2171
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002172 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002173 /*
2174 * We're interested only in the user space callchain
2175 * leading to the syscall, allow overriding that for
2176 * debugging reasons using --kernel_syscall_callchains
2177 */
2178 sys_exit->attr.exclude_callchain_kernel = 1;
2179 }
2180
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002181 trace->syscalls.events.sys_enter = sys_enter;
2182 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002183
2184 ret = 0;
2185out:
2186 return ret;
2187
2188out_delete_sys_exit:
2189 perf_evsel__delete_priv(sys_exit);
2190out_delete_sys_enter:
2191 perf_evsel__delete_priv(sys_enter);
2192 goto out;
2193}
2194
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002195static int trace__set_ev_qualifier_filter(struct trace *trace)
2196{
2197 int err = -1;
2198 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2199 trace->ev_qualifier_ids.nr,
2200 trace->ev_qualifier_ids.entries);
2201
2202 if (filter == NULL)
2203 goto out_enomem;
2204
2205 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2206 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2207
2208 free(filter);
2209out:
2210 return err;
2211out_enomem:
2212 errno = ENOMEM;
2213 goto out;
2214}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002215
Namhyung Kimf15eb532012-10-05 14:02:16 +09002216static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002217{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002218 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002219 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002220 int err = -1, i;
2221 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002222 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002223 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002224
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002225 trace->live = true;
2226
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002227 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002228 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002229
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002230 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002231 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002232
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002233 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2234 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2235 if (pgfault_maj == NULL)
2236 goto out_error_mem;
2237 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002238 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002239
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002240 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2241 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2242 if (pgfault_min == NULL)
2243 goto out_error_mem;
2244 perf_evlist__add(evlist, pgfault_min);
2245 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002246
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002247 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002248 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2249 trace__sched_stat_runtime))
2250 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002251
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002252 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2253 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002254 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002255 goto out_delete_evlist;
2256 }
2257
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002258 err = trace__symbols_init(trace, evlist);
2259 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002260 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002261 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002262 }
2263
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002264 perf_evlist__config(evlist, &trace->opts, NULL);
2265
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002266 if (callchain_param.enabled) {
2267 bool use_identifier = false;
2268
2269 if (trace->syscalls.events.sys_exit) {
2270 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2271 &trace->opts, &callchain_param);
2272 use_identifier = true;
2273 }
2274
2275 if (pgfault_maj) {
2276 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2277 use_identifier = true;
2278 }
2279
2280 if (pgfault_min) {
2281 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2282 use_identifier = true;
2283 }
2284
2285 if (use_identifier) {
2286 /*
2287 * Now we have evsels with different sample_ids, use
2288 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2289 * from a fixed position in each ring buffer record.
2290 *
2291 * As of this the changeset introducing this comment, this
2292 * isn't strictly needed, as the fields that can come before
2293 * PERF_SAMPLE_ID are all used, but we'll probably disable
2294 * some of those for things like copying the payload of
2295 * pointer syscall arguments, and for vfs_getname we don't
2296 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2297 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2298 */
2299 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2300 perf_evlist__reset_sample_bit(evlist, ID);
2301 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002302 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002303
Namhyung Kimf15eb532012-10-05 14:02:16 +09002304 signal(SIGCHLD, sig_handler);
2305 signal(SIGINT, sig_handler);
2306
2307 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002308 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002309 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002310 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002311 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002312 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002313 }
2314 }
2315
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002316 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002317 if (err < 0)
2318 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002319
Wang Nanba504232016-02-26 09:31:54 +00002320 err = bpf__apply_obj_config();
2321 if (err) {
2322 char errbuf[BUFSIZ];
2323
2324 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2325 pr_err("ERROR: Apply config to BPF failed: %s\n",
2326 errbuf);
2327 goto out_error_open;
2328 }
2329
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002330 /*
2331 * Better not use !target__has_task() here because we need to cover the
2332 * case where no threads were specified in the command line, but a
2333 * workload was, and in that case we will fill in the thread_map when
2334 * we fork the workload in perf_evlist__prepare_workload.
2335 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002336 if (trace->filter_pids.nr > 0)
2337 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002338 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002339 err = perf_evlist__set_filter_pid(evlist, getpid());
2340
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002341 if (err < 0)
2342 goto out_error_mem;
2343
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002344 if (trace->ev_qualifier_ids.nr > 0) {
2345 err = trace__set_ev_qualifier_filter(trace);
2346 if (err < 0)
2347 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002348
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002349 pr_debug("event qualifier tracepoint filter: %s\n",
2350 trace->syscalls.events.sys_exit->filter);
2351 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002352
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002353 err = perf_evlist__apply_filters(evlist, &evsel);
2354 if (err < 0)
2355 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002356
Jiri Olsaf8850372013-11-28 17:57:22 +01002357 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002358 if (err < 0)
2359 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002360
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002361 if (!target__none(&trace->opts.target))
2362 perf_evlist__enable(evlist);
2363
Namhyung Kimf15eb532012-10-05 14:02:16 +09002364 if (forks)
2365 perf_evlist__start_workload(evlist);
2366
Jiri Olsae13798c2015-06-23 00:36:02 +02002367 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002368 evlist->threads->nr > 1 ||
2369 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002370again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002371 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002372
2373 for (i = 0; i < evlist->nr_mmaps; i++) {
2374 union perf_event *event;
2375
2376 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002377 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002378
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002379 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002380
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002381 err = perf_evlist__parse_sample(evlist, event, &sample);
2382 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002383 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002384 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002385 }
2386
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002387 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002388next_event:
2389 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002390
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002391 if (interrupted)
2392 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002393
2394 if (done && !draining) {
2395 perf_evlist__disable(evlist);
2396 draining = true;
2397 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002398 }
2399 }
2400
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002401 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002402 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002403
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002404 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2405 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2406 draining = true;
2407
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002408 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002409 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002410 } else {
2411 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002412 }
2413
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002414out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002415 thread__zput(trace->current);
2416
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002417 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002418
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002419 if (!err) {
2420 if (trace->summary)
2421 trace__fprintf_thread_summary(trace, trace->output);
2422
2423 if (trace->show_tool_stats) {
2424 fprintf(trace->output, "Stats:\n "
2425 " vfs_getname : %" PRIu64 "\n"
2426 " proc_getname: %" PRIu64 "\n",
2427 trace->stats.vfs_getname,
2428 trace->stats.proc_getname);
2429 }
2430 }
David Ahernbf2575c2013-10-08 21:26:53 -06002431
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002432out_delete_evlist:
2433 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002434 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002435 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002436 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002437{
2438 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002439
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002440out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002441 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002442 goto out_error;
2443
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002444out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002445 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002446 goto out_error;
2447
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002448out_error_mmap:
2449 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2450 goto out_error;
2451
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002452out_error_open:
2453 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2454
2455out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002456 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302457 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002458
2459out_error_apply_filters:
2460 fprintf(trace->output,
2461 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2462 evsel->filter, perf_evsel__name(evsel), errno,
2463 strerror_r(errno, errbuf, sizeof(errbuf)));
2464 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002465}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002466out_error_mem:
2467 fprintf(trace->output, "Not enough memory to run!\n");
2468 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002469
2470out_errno:
2471 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2472 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002473}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002474
David Ahern6810fc92013-08-28 22:29:52 -06002475static int trace__replay(struct trace *trace)
2476{
2477 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002478 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002479 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002480 struct perf_data_file file = {
2481 .path = input_name,
2482 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002483 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002484 };
David Ahern6810fc92013-08-28 22:29:52 -06002485 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002486 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002487 int err = -1;
2488
2489 trace->tool.sample = trace__process_sample;
2490 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002491 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002492 trace->tool.comm = perf_event__process_comm;
2493 trace->tool.exit = perf_event__process_exit;
2494 trace->tool.fork = perf_event__process_fork;
2495 trace->tool.attr = perf_event__process_attr;
2496 trace->tool.tracing_data = perf_event__process_tracing_data;
2497 trace->tool.build_id = perf_event__process_build_id;
2498
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002499 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002500 trace->tool.ordering_requires_timestamps = true;
2501
2502 /* add tid to output */
2503 trace->multiple_threads = true;
2504
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002505 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002506 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002507 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002508
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002509 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002510 goto out;
2511
David Ahern8fb598e2013-09-28 13:13:00 -06002512 trace->host = &session->machines.host;
2513
David Ahern6810fc92013-08-28 22:29:52 -06002514 err = perf_session__set_tracepoints_handlers(session, handlers);
2515 if (err)
2516 goto out;
2517
Namhyung Kim003824e2013-11-12 15:25:00 +09002518 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2519 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002520 /* older kernels have syscalls tp versus raw_syscalls */
2521 if (evsel == NULL)
2522 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2523 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002524
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002525 if (evsel &&
2526 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2527 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002528 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2529 goto out;
2530 }
2531
2532 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2533 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002534 if (evsel == NULL)
2535 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2536 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002537 if (evsel &&
2538 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2539 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002540 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002541 goto out;
2542 }
2543
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002544 evlist__for_each(session->evlist, evsel) {
2545 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2546 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2547 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2548 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2549 evsel->handler = trace__pgfault;
2550 }
2551
David Ahernbdc89662013-08-28 22:29:53 -06002552 err = parse_target_str(trace);
2553 if (err != 0)
2554 goto out;
2555
David Ahern6810fc92013-08-28 22:29:52 -06002556 setup_pager();
2557
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002558 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002559 if (err)
2560 pr_err("Failed to process events, error %d", err);
2561
David Ahernbf2575c2013-10-08 21:26:53 -06002562 else if (trace->summary)
2563 trace__fprintf_thread_summary(trace, trace->output);
2564
David Ahern6810fc92013-08-28 22:29:52 -06002565out:
2566 perf_session__delete(session);
2567
2568 return err;
2569}
2570
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002571static size_t trace__fprintf_threads_header(FILE *fp)
2572{
2573 size_t printed;
2574
Pekka Enberg99ff7152013-11-12 16:42:14 +02002575 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002576
2577 return printed;
2578}
2579
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002580DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2581 struct stats *stats;
2582 double msecs;
2583 int syscall;
2584)
2585{
2586 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2587 struct stats *stats = source->priv;
2588
2589 entry->syscall = source->i;
2590 entry->stats = stats;
2591 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2592}
2593
David Ahernbf2575c2013-10-08 21:26:53 -06002594static size_t thread__dump_stats(struct thread_trace *ttrace,
2595 struct trace *trace, FILE *fp)
2596{
David Ahernbf2575c2013-10-08 21:26:53 -06002597 size_t printed = 0;
2598 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002599 struct rb_node *nd;
2600 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002601
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002602 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002603 return 0;
2604
2605 printed += fprintf(fp, "\n");
2606
Milian Wolff834fd462015-08-06 11:24:29 +02002607 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2608 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2609 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002610
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002611 resort_rb__for_each(nd, syscall_stats) {
2612 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002613 if (stats) {
2614 double min = (double)(stats->min) / NSEC_PER_MSEC;
2615 double max = (double)(stats->max) / NSEC_PER_MSEC;
2616 double avg = avg_stats(stats);
2617 double pct;
2618 u64 n = (u64) stats->n;
2619
2620 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2621 avg /= NSEC_PER_MSEC;
2622
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002623 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002624 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002625 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002626 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002627 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002628 }
David Ahernbf2575c2013-10-08 21:26:53 -06002629 }
2630
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002631 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002632 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002633
2634 return printed;
2635}
2636
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002637static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002638{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002639 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002640 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002641 double ratio;
2642
2643 if (ttrace == NULL)
2644 return 0;
2645
2646 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2647
Pekka Enberg15e65c62013-11-14 18:43:30 +02002648 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002649 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002650 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002651 if (ttrace->pfmaj)
2652 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2653 if (ttrace->pfmin)
2654 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002655 if (trace->sched)
2656 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2657 else if (fputc('\n', fp) != EOF)
2658 ++printed;
2659
David Ahernbf2575c2013-10-08 21:26:53 -06002660 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002661
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002662 return printed;
2663}
David Ahern896cbb52013-09-28 13:12:59 -06002664
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002665static unsigned long thread__nr_events(struct thread_trace *ttrace)
2666{
2667 return ttrace ? ttrace->nr_events : 0;
2668}
2669
2670DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2671 struct thread *thread;
2672)
2673{
2674 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002675}
2676
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002677static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2678{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002679 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2680 size_t printed = trace__fprintf_threads_header(fp);
2681 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002682
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002683 if (threads == NULL) {
2684 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2685 return 0;
2686 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002687
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002688 resort_rb__for_each(nd, threads)
2689 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2690
2691 resort_rb__delete(threads);
2692
2693 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002694}
2695
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002696static int trace__set_duration(const struct option *opt, const char *str,
2697 int unset __maybe_unused)
2698{
2699 struct trace *trace = opt->value;
2700
2701 trace->duration_filter = atof(str);
2702 return 0;
2703}
2704
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002705static int trace__set_filter_pids(const struct option *opt, const char *str,
2706 int unset __maybe_unused)
2707{
2708 int ret = -1;
2709 size_t i;
2710 struct trace *trace = opt->value;
2711 /*
2712 * FIXME: introduce a intarray class, plain parse csv and create a
2713 * { int nr, int entries[] } struct...
2714 */
2715 struct intlist *list = intlist__new(str);
2716
2717 if (list == NULL)
2718 return -1;
2719
2720 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2721 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2722
2723 if (trace->filter_pids.entries == NULL)
2724 goto out;
2725
2726 trace->filter_pids.entries[0] = getpid();
2727
2728 for (i = 1; i < trace->filter_pids.nr; ++i)
2729 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2730
2731 intlist__delete(list);
2732 ret = 0;
2733out:
2734 return ret;
2735}
2736
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002737static int trace__open_output(struct trace *trace, const char *filename)
2738{
2739 struct stat st;
2740
2741 if (!stat(filename, &st) && st.st_size) {
2742 char oldname[PATH_MAX];
2743
2744 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2745 unlink(oldname);
2746 rename(filename, oldname);
2747 }
2748
2749 trace->output = fopen(filename, "w");
2750
2751 return trace->output == NULL ? -errno : 0;
2752}
2753
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002754static int parse_pagefaults(const struct option *opt, const char *str,
2755 int unset __maybe_unused)
2756{
2757 int *trace_pgfaults = opt->value;
2758
2759 if (strcmp(str, "all") == 0)
2760 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2761 else if (strcmp(str, "maj") == 0)
2762 *trace_pgfaults |= TRACE_PFMAJ;
2763 else if (strcmp(str, "min") == 0)
2764 *trace_pgfaults |= TRACE_PFMIN;
2765 else
2766 return -1;
2767
2768 return 0;
2769}
2770
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002771static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2772{
2773 struct perf_evsel *evsel;
2774
2775 evlist__for_each(evlist, evsel)
2776 evsel->handler = handler;
2777}
2778
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002779int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2780{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002781 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002782 "perf trace [<options>] [<command>]",
2783 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002784 "perf trace record [<options>] [<command>]",
2785 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002786 NULL
2787 };
2788 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002789 .syscalls = {
2790 . max = -1,
2791 },
2792 .opts = {
2793 .target = {
2794 .uid = UINT_MAX,
2795 .uses_mmap = true,
2796 },
2797 .user_freq = UINT_MAX,
2798 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002799 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002800 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002801 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002802 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002803 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002804 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002805 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002806 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002807 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002808 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002809 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002810 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002811 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002812 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2813 "event selector. use 'perf list' to list available events",
2814 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002815 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2816 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002817 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002818 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002819 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002820 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002821 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2822 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002823 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002824 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002825 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2826 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002827 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002828 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002829 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002830 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002831 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002832 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002833 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2834 "number of mmap data pages",
2835 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002836 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002837 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002838 OPT_CALLBACK(0, "duration", &trace, "float",
2839 "show only events with duration > N.M ms",
2840 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002841 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002842 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002843 OPT_BOOLEAN('T', "time", &trace.full_time,
2844 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002845 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2846 "Show only syscall summary with statistics"),
2847 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2848 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002849 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2850 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002851 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002852 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002853 OPT_CALLBACK(0, "call-graph", &trace.opts,
2854 "record_mode[,record_size]", record_callchain_help,
2855 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002856 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2857 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002858 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2859 "Set the minimum stack depth when parsing the callchain, "
2860 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002861 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2862 "Set the maximum stack depth when parsing the callchain, "
2863 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002864 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002865 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2866 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002867 OPT_END()
2868 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002869 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002870 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002871 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002872 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002873 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002874
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002875 signal(SIGSEGV, sighandler_dump_stack);
2876 signal(SIGFPE, sighandler_dump_stack);
2877
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002878 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002879 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002880
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002881 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002882 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002883 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002884 goto out;
2885 }
2886
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002887 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2888 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002889
Wang Nand7888572016-04-08 15:07:24 +00002890 err = bpf__setup_stdout(trace.evlist);
2891 if (err) {
2892 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2893 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2894 goto out;
2895 }
2896
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002897 err = -1;
2898
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002899 if (trace.trace_pgfaults) {
2900 trace.opts.sample_address = true;
2901 trace.opts.sample_time = true;
2902 }
2903
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002904 if (trace.opts.mmap_pages == UINT_MAX)
2905 mmap_pages_user_set = false;
2906
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002907 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002908 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002909 max_stack_user_set = false;
2910 }
2911
2912#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002913 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002914 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2915#endif
2916
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002917 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002918 if (!mmap_pages_user_set && geteuid() == 0)
2919 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2920
Milian Wolff566a0882016-04-08 13:34:15 +02002921 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002922 }
Milian Wolff566a0882016-04-08 13:34:15 +02002923
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002924 if (trace.evlist->nr_entries > 0)
2925 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2926
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002927 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2928 return trace__record(&trace, argc-1, &argv[1]);
2929
2930 /* summary_only implies summary option, but don't overwrite summary if set */
2931 if (trace.summary_only)
2932 trace.summary = trace.summary_only;
2933
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002934 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2935 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002936 pr_err("Please specify something to trace.\n");
2937 return -1;
2938 }
2939
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002940 if (!trace.trace_syscalls && ev_qualifier_str) {
2941 pr_err("The -e option can't be used with --no-syscalls.\n");
2942 goto out;
2943 }
2944
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002945 if (output_name != NULL) {
2946 err = trace__open_output(&trace, output_name);
2947 if (err < 0) {
2948 perror("failed to create output file");
2949 goto out;
2950 }
2951 }
2952
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002953 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2954
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002955 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002956 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002957 struct strlist_config slist_config = {
2958 .dirname = system_path(STRACE_GROUPS_DIR),
2959 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002960
2961 trace.not_ev_qualifier = *s == '!';
2962 if (trace.not_ev_qualifier)
2963 ++s;
Arnaldo Carvalho de Melo005438a82015-07-20 12:02:09 -03002964 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002965 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002966 fputs("Not enough memory to parse event qualifier",
2967 trace.output);
2968 err = -ENOMEM;
2969 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002970 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002971
2972 err = trace__validate_ev_qualifier(&trace);
2973 if (err)
2974 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002975 }
2976
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002977 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002978 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002979 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002980 fprintf(trace.output, "%s", bf);
2981 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002982 }
2983
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002984 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002985 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002986 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002987 fprintf(trace.output, "%s", bf);
2988 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002989 }
2990
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002991 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002992 trace.opts.target.system_wide = true;
2993
David Ahern6810fc92013-08-28 22:29:52 -06002994 if (input_name)
2995 err = trace__replay(&trace);
2996 else
2997 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002998
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002999out_close:
3000 if (output_name != NULL)
3001 fclose(trace.output);
3002out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003003 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003004}