blob: 0fd8bfb77f65278172c304c16346f14041070ace [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020043#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030044#include <linux/filter.h>
45#include <linux/audit.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030046#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030047#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030048#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030049
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030050#ifndef O_CLOEXEC
51# define O_CLOEXEC 02000000
52#endif
53
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030054struct trace {
55 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030056 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030057 struct {
58 int max;
59 struct syscall *table;
60 struct {
61 struct perf_evsel *sys_enter,
62 *sys_exit;
63 } events;
64 } syscalls;
65 struct record_opts opts;
66 struct perf_evlist *evlist;
67 struct machine *host;
68 struct thread *current;
69 u64 base_time;
70 FILE *output;
71 unsigned long nr_events;
72 struct strlist *ev_qualifier;
73 struct {
74 size_t nr;
75 int *entries;
76 } ev_qualifier_ids;
77 struct intlist *tid_list;
78 struct intlist *pid_list;
79 struct {
80 size_t nr;
81 pid_t *entries;
82 } filter_pids;
83 double duration_filter;
84 double runtime_ms;
85 struct {
86 u64 vfs_getname,
87 proc_getname;
88 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030089 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030090 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030091 bool not_ev_qualifier;
92 bool live;
93 bool full_time;
94 bool sched;
95 bool multiple_threads;
96 bool summary;
97 bool summary_only;
98 bool show_comm;
99 bool show_tool_stats;
100 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300101 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300102 bool force;
103 bool vfs_getname;
104 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300105 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300107
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300108struct tp_field {
109 int offset;
110 union {
111 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
112 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
113 };
114};
115
116#define TP_UINT_FIELD(bits) \
117static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
118{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500119 u##bits value; \
120 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
121 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300122}
123
124TP_UINT_FIELD(8);
125TP_UINT_FIELD(16);
126TP_UINT_FIELD(32);
127TP_UINT_FIELD(64);
128
129#define TP_UINT_FIELD__SWAPPED(bits) \
130static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
131{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500132 u##bits value; \
133 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300134 return bswap_##bits(value);\
135}
136
137TP_UINT_FIELD__SWAPPED(16);
138TP_UINT_FIELD__SWAPPED(32);
139TP_UINT_FIELD__SWAPPED(64);
140
141static int tp_field__init_uint(struct tp_field *field,
142 struct format_field *format_field,
143 bool needs_swap)
144{
145 field->offset = format_field->offset;
146
147 switch (format_field->size) {
148 case 1:
149 field->integer = tp_field__u8;
150 break;
151 case 2:
152 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
153 break;
154 case 4:
155 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
156 break;
157 case 8:
158 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
159 break;
160 default:
161 return -1;
162 }
163
164 return 0;
165}
166
167static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
168{
169 return sample->raw_data + field->offset;
170}
171
172static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
173{
174 field->offset = format_field->offset;
175 field->pointer = tp_field__ptr;
176 return 0;
177}
178
179struct syscall_tp {
180 struct tp_field id;
181 union {
182 struct tp_field args, ret;
183 };
184};
185
186static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
187 struct tp_field *field,
188 const char *name)
189{
190 struct format_field *format_field = perf_evsel__field(evsel, name);
191
192 if (format_field == NULL)
193 return -1;
194
195 return tp_field__init_uint(field, format_field, evsel->needs_swap);
196}
197
198#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
199 ({ struct syscall_tp *sc = evsel->priv;\
200 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
201
202static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
203 struct tp_field *field,
204 const char *name)
205{
206 struct format_field *format_field = perf_evsel__field(evsel, name);
207
208 if (format_field == NULL)
209 return -1;
210
211 return tp_field__init_ptr(field, format_field);
212}
213
214#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
215 ({ struct syscall_tp *sc = evsel->priv;\
216 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
217
218static void perf_evsel__delete_priv(struct perf_evsel *evsel)
219{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300220 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300221 perf_evsel__delete(evsel);
222}
223
Namhyung Kim96695d42013-11-12 08:51:45 -0300224static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
225{
226 evsel->priv = malloc(sizeof(struct syscall_tp));
227 if (evsel->priv != NULL) {
228 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
229 goto out_delete;
230
231 evsel->handler = handler;
232 return 0;
233 }
234
235 return -ENOMEM;
236
237out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300238 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300239 return -ENOENT;
240}
241
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300242static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300243{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245
David Ahern9aca7f12013-12-04 19:41:39 -0700246 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200247 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700248 evsel = perf_evsel__newtp("syscalls", direction);
249
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200250 if (IS_ERR(evsel))
251 return NULL;
252
253 if (perf_evsel__init_syscall_tp(evsel, handler))
254 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300255
256 return evsel;
257
258out_delete:
259 perf_evsel__delete_priv(evsel);
260 return NULL;
261}
262
263#define perf_evsel__sc_tp_uint(evsel, name, sample) \
264 ({ struct syscall_tp *fields = evsel->priv; \
265 fields->name.integer(&fields->name, sample); })
266
267#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
268 ({ struct syscall_tp *fields = evsel->priv; \
269 fields->name.pointer(&fields->name, sample); })
270
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271struct syscall_arg {
272 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300273 struct thread *thread;
274 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300275 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300276 u8 idx;
277 u8 mask;
278};
279
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300280struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300281 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282 int nr_entries;
283 const char **entries;
284};
285
286#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
287 .nr_entries = ARRAY_SIZE(array), \
288 .entries = array, \
289}
290
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300291#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
292 .offset = off, \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300297static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
298 const char *intfmt,
299 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300302 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303
304 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300305 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306
307 return scnprintf(bf, size, "%s", sa->entries[idx]);
308}
309
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300310static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
311 struct syscall_arg *arg)
312{
313 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
314}
315
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316#define SCA_STRARRAY syscall_arg__scnprintf_strarray
317
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300318#if defined(__i386__) || defined(__x86_64__)
319/*
320 * FIXME: Make this available to all arches as soon as the ioctl beautifier
321 * gets rewritten to support all arches.
322 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300323static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
324 struct syscall_arg *arg)
325{
326 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
327}
328
329#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300330#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300331
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300332static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
333 struct syscall_arg *arg);
334
335#define SCA_FD syscall_arg__scnprintf_fd
336
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300337#ifndef AT_FDCWD
338#define AT_FDCWD -100
339#endif
340
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300341static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
342 struct syscall_arg *arg)
343{
344 int fd = arg->val;
345
346 if (fd == AT_FDCWD)
347 return scnprintf(bf, size, "CWD");
348
349 return syscall_arg__scnprintf_fd(bf, size, arg);
350}
351
352#define SCA_FDAT syscall_arg__scnprintf_fd_at
353
354static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
355 struct syscall_arg *arg);
356
357#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
358
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300359static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300360 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300361{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300362 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300363}
364
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300365#define SCA_HEX syscall_arg__scnprintf_hex
366
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300367static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
368 struct syscall_arg *arg)
369{
370 return scnprintf(bf, size, "%d", arg->val);
371}
372
373#define SCA_INT syscall_arg__scnprintf_int
374
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300375static const char *bpf_cmd[] = {
376 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
377 "MAP_GET_NEXT_KEY", "PROG_LOAD",
378};
379static DEFINE_STRARRAY(bpf_cmd);
380
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300381static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
382static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300383
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300384static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
385static DEFINE_STRARRAY(itimers);
386
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300387static const char *keyctl_options[] = {
388 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
389 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
390 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
391 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
392 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
393};
394static DEFINE_STRARRAY(keyctl_options);
395
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300396static const char *whences[] = { "SET", "CUR", "END",
397#ifdef SEEK_DATA
398"DATA",
399#endif
400#ifdef SEEK_HOLE
401"HOLE",
402#endif
403};
404static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300405
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300406static const char *fcntl_cmds[] = {
407 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
408 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
409 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
410 "F_GETOWNER_UIDS",
411};
412static DEFINE_STRARRAY(fcntl_cmds);
413
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300414static const char *rlimit_resources[] = {
415 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
416 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
417 "RTTIME",
418};
419static DEFINE_STRARRAY(rlimit_resources);
420
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300421static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
422static DEFINE_STRARRAY(sighow);
423
David Ahern4f8c1b72013-09-22 19:45:00 -0600424static const char *clockid[] = {
425 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300426 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
427 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600428};
429static DEFINE_STRARRAY(clockid);
430
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300431static const char *socket_families[] = {
432 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
433 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
434 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
435 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
436 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
437 "ALG", "NFC", "VSOCK",
438};
439static DEFINE_STRARRAY(socket_families);
440
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300441static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
442 struct syscall_arg *arg)
443{
444 size_t printed = 0;
445 int mode = arg->val;
446
447 if (mode == F_OK) /* 0 */
448 return scnprintf(bf, size, "F");
449#define P_MODE(n) \
450 if (mode & n##_OK) { \
451 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
452 mode &= ~n##_OK; \
453 }
454
455 P_MODE(R);
456 P_MODE(W);
457 P_MODE(X);
458#undef P_MODE
459
460 if (mode)
461 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
462
463 return printed;
464}
465
466#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
467
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300468static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
469 struct syscall_arg *arg);
470
471#define SCA_FILENAME syscall_arg__scnprintf_filename
472
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300473static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
474 struct syscall_arg *arg)
475{
476 int printed = 0, flags = arg->val;
477
478#define P_FLAG(n) \
479 if (flags & O_##n) { \
480 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
481 flags &= ~O_##n; \
482 }
483
484 P_FLAG(CLOEXEC);
485 P_FLAG(NONBLOCK);
486#undef P_FLAG
487
488 if (flags)
489 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
490
491 return printed;
492}
493
494#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
495
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300496#if defined(__i386__) || defined(__x86_64__)
497/*
498 * FIXME: Make this available to all arches.
499 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300500#define TCGETS 0x5401
501
502static const char *tioctls[] = {
503 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
504 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
505 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
506 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
507 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
508 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
509 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
510 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
511 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
512 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
513 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
514 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
515 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
516 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
517 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
518};
519
520static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300521#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300522
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300523#ifndef GRND_NONBLOCK
524#define GRND_NONBLOCK 0x0001
525#endif
526#ifndef GRND_RANDOM
527#define GRND_RANDOM 0x0002
528#endif
529
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300530static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
531 struct syscall_arg *arg)
532{
533 int printed = 0, flags = arg->val;
534
535#define P_FLAG(n) \
536 if (flags & GRND_##n) { \
537 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
538 flags &= ~GRND_##n; \
539 }
540
541 P_FLAG(RANDOM);
542 P_FLAG(NONBLOCK);
543#undef P_FLAG
544
545 if (flags)
546 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
547
548 return printed;
549}
550
551#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
552
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300553#define STRARRAY(arg, name, array) \
554 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
555 .arg_parm = { [arg] = &strarray__##array, }
556
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300557#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300558#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300559#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300560#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300561#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300562#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300563#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300564#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300565#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300566#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300567#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300568#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300569#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300570#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300571
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300572static struct syscall_fmt {
573 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300574 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300575 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300576 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300577 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300578 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300579 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300580 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300581} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300582 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300583 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300584 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300585 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300586 { .name = "brk", .hexret = true,
587 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300588 { .name = "chdir", .errmsg = true, },
589 { .name = "chmod", .errmsg = true, },
590 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600591 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300592 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300593 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300594 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300595 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300596 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300597 { .name = "dup", .errmsg = true, },
598 { .name = "dup2", .errmsg = true, },
599 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300600 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300601 { .name = "eventfd2", .errmsg = true,
602 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300603 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300604 { .name = "fadvise64", .errmsg = true, },
605 { .name = "fallocate", .errmsg = true, },
606 { .name = "fchdir", .errmsg = true, },
607 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300608 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300609 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300610 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300611 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300612 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300613 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300614 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300615 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300616 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300617 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300618 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
619 { .name = "fsetxattr", .errmsg = true, },
620 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300621 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300622 { .name = "fstatfs", .errmsg = true, },
623 { .name = "fsync", .errmsg = true, },
624 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300625 { .name = "futex", .errmsg = true,
626 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300627 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300628 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300629 { .name = "getdents", .errmsg = true, },
630 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300631 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300632 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300633 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300634 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300635 { .name = "getrandom", .errmsg = true,
636 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300637 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300638 { .name = "getxattr", .errmsg = true, },
639 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300640 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300641 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300642#if defined(__i386__) || defined(__x86_64__)
643/*
644 * FIXME: Make this available to all arches.
645 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300646 [1] = SCA_STRHEXARRAY, /* cmd */
647 [2] = SCA_HEX, /* arg */ },
648 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300649#else
650 [2] = SCA_HEX, /* arg */ }, },
651#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300652 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300653 { .name = "kill", .errmsg = true,
654 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300655 { .name = "lchown", .errmsg = true, },
656 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300657 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300658 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300659 { .name = "listxattr", .errmsg = true, },
660 { .name = "llistxattr", .errmsg = true, },
661 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300662 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300663 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300664 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300665 { .name = "lsetxattr", .errmsg = true, },
666 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
667 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300668 { .name = "madvise", .errmsg = true,
669 .arg_scnprintf = { [0] = SCA_HEX, /* start */
670 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300671 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300672 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300673 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
674 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300675 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300676 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300677 { .name = "mlock", .errmsg = true,
678 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
679 { .name = "mlockall", .errmsg = true,
680 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300681 { .name = "mmap", .hexret = true,
Jiri Olsa2761eda2017-05-31 13:35:57 +0200682/* The standard mmap maps to old_mmap on s390x */
683#if defined(__s390x__)
684 .alias = "old_mmap",
685#endif
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300686 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300687 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300688 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300689 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300690 .arg_scnprintf = { [0] = SCA_HEX, /* start */
691 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300692 { .name = "mq_unlink", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300694 { .name = "mremap", .hexret = true,
695 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300696 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300697 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300698 { .name = "munlock", .errmsg = true,
699 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300700 { .name = "munmap", .errmsg = true,
701 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300702 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300703 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300704 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300705 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300706 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300707 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300708 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300709 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
710 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300711 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300712 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
713 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300714 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300715 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300716 [3] = SCA_FD, /* group_fd */
717 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300718 { .name = "pipe2", .errmsg = true,
719 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300720 { .name = "poll", .errmsg = true, .timeout = true, },
721 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300722 { .name = "pread", .errmsg = true, .alias = "pread64", },
723 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300724 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300725 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
726 { .name = "pwritev", .errmsg = true, },
727 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300728 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300729 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300730 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300731 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300732 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300733 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300734 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300735 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300736 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300737 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300738 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300739 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300740 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300741 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300742 { .name = "rt_sigaction", .errmsg = true,
743 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300744 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300745 { .name = "rt_sigqueueinfo", .errmsg = true,
746 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
747 { .name = "rt_tgsigqueueinfo", .errmsg = true,
748 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300749 { .name = "sched_getattr", .errmsg = true, },
750 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300751 { .name = "sched_setscheduler", .errmsg = true,
752 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300753 { .name = "seccomp", .errmsg = true,
754 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
755 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300756 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300757 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300758 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300759 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300760 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300761 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300762 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300763 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300764 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300765 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300766 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300767 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300768 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300769 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300770 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
771 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300772 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300773 { .name = "socketpair", .errmsg = true,
774 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
775 [1] = SCA_SK_TYPE, /* type */ },
776 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300777 { .name = "stat", .errmsg = true, .alias = "newstat", },
778 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300779 { .name = "swapoff", .errmsg = true,
780 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
781 { .name = "swapon", .errmsg = true,
782 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300783 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300784 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300785 { .name = "tgkill", .errmsg = true,
786 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
787 { .name = "tkill", .errmsg = true,
788 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300789 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300790 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300791 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300792 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
793 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300794 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300795 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
796 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300797 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300798 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300799 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300800 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300801 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300802 { .name = "write", .errmsg = true, },
803 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300804};
805
806static int syscall_fmt__cmp(const void *name, const void *fmtp)
807{
808 const struct syscall_fmt *fmt = fmtp;
809 return strcmp(name, fmt->name);
810}
811
812static struct syscall_fmt *syscall_fmt__find(const char *name)
813{
814 const int nmemb = ARRAY_SIZE(syscall_fmts);
815 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
816}
817
818struct syscall {
819 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300820 int nr_args;
821 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300822 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300823 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300824 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300825 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300826 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300827};
828
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -0300829/*
830 * We need to have this 'calculated' boolean because in some cases we really
831 * don't know what is the duration of a syscall, for instance, when we start
832 * a session and some threads are waiting for a syscall to finish, say 'poll',
833 * in which case all we can do is to print "( ? ) for duration and for the
834 * start timestamp.
835 */
836static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200837{
838 double duration = (double)t / NSEC_PER_MSEC;
839 size_t printed = fprintf(fp, "(");
840
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -0300841 if (!calculated)
842 printed += fprintf(fp, " ? ");
843 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200844 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
845 else if (duration >= 0.01)
846 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
847 else
848 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300849 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200850}
851
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300852/**
853 * filename.ptr: The filename char pointer that will be vfs_getname'd
854 * filename.entry_str_pos: Where to insert the string translated from
855 * filename.ptr by the vfs_getname tracepoint/kprobe.
856 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300857struct thread_trace {
858 u64 entry_time;
859 u64 exit_time;
860 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300861 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400862 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300863 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300864 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300865 struct {
866 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300867 short int entry_str_pos;
868 bool pending_open;
869 unsigned int namelen;
870 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300871 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300872 struct {
873 int max;
874 char **table;
875 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600876
877 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300878};
879
880static struct thread_trace *thread_trace__new(void)
881{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300882 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
883
884 if (ttrace)
885 ttrace->paths.max = -1;
886
David Ahernbf2575c2013-10-08 21:26:53 -0600887 ttrace->syscall_stats = intlist__new(NULL);
888
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300889 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890}
891
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300892static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300893{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300894 struct thread_trace *ttrace;
895
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300896 if (thread == NULL)
897 goto fail;
898
Namhyung Kim89dceb22014-10-06 09:46:03 +0900899 if (thread__priv(thread) == NULL)
900 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300901
Namhyung Kim89dceb22014-10-06 09:46:03 +0900902 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300903 goto fail;
904
Namhyung Kim89dceb22014-10-06 09:46:03 +0900905 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300906 ++ttrace->nr_events;
907
908 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300910 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300911 "WARNING: not enough memory, dropping samples!\n");
912 return NULL;
913}
914
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400915#define TRACE_PFMAJ (1 << 0)
916#define TRACE_PFMIN (1 << 1)
917
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300918static const size_t trace__entry_str_size = 2048;
919
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300920static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300921{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900922 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300923
924 if (fd > ttrace->paths.max) {
925 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
926
927 if (npath == NULL)
928 return -1;
929
930 if (ttrace->paths.max != -1) {
931 memset(npath + ttrace->paths.max + 1, 0,
932 (fd - ttrace->paths.max) * sizeof(char *));
933 } else {
934 memset(npath, 0, (fd + 1) * sizeof(char *));
935 }
936
937 ttrace->paths.table = npath;
938 ttrace->paths.max = fd;
939 }
940
941 ttrace->paths.table[fd] = strdup(pathname);
942
943 return ttrace->paths.table[fd] != NULL ? 0 : -1;
944}
945
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300946static int thread__read_fd_path(struct thread *thread, int fd)
947{
948 char linkname[PATH_MAX], pathname[PATH_MAX];
949 struct stat st;
950 int ret;
951
952 if (thread->pid_ == thread->tid) {
953 scnprintf(linkname, sizeof(linkname),
954 "/proc/%d/fd/%d", thread->pid_, fd);
955 } else {
956 scnprintf(linkname, sizeof(linkname),
957 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
958 }
959
960 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
961 return -1;
962
963 ret = readlink(linkname, pathname, sizeof(pathname));
964
965 if (ret < 0 || ret > st.st_size)
966 return -1;
967
968 pathname[ret] = '\0';
969 return trace__set_fd_pathname(thread, fd, pathname);
970}
971
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300972static const char *thread__fd_path(struct thread *thread, int fd,
973 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300974{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900975 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300976
977 if (ttrace == NULL)
978 return NULL;
979
980 if (fd < 0)
981 return NULL;
982
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300983 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300984 if (!trace->live)
985 return NULL;
986 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300987 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300988 return NULL;
989 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300990
991 return ttrace->paths.table[fd];
992}
993
994static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
995 struct syscall_arg *arg)
996{
997 int fd = arg->val;
998 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300999 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001000
1001 if (path)
1002 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1003
1004 return printed;
1005}
1006
1007static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1008 struct syscall_arg *arg)
1009{
1010 int fd = arg->val;
1011 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001012 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001013
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001014 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1015 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001016
1017 return printed;
1018}
1019
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001020static void thread__set_filename_pos(struct thread *thread, const char *bf,
1021 unsigned long ptr)
1022{
1023 struct thread_trace *ttrace = thread__priv(thread);
1024
1025 ttrace->filename.ptr = ptr;
1026 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1027}
1028
1029static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1030 struct syscall_arg *arg)
1031{
1032 unsigned long ptr = arg->val;
1033
1034 if (!arg->trace->vfs_getname)
1035 return scnprintf(bf, size, "%#x", ptr);
1036
1037 thread__set_filename_pos(arg->thread, bf, ptr);
1038 return 0;
1039}
1040
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001041static bool trace__filter_duration(struct trace *trace, double t)
1042{
1043 return t < (trace->duration_filter * NSEC_PER_MSEC);
1044}
1045
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001046static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001047{
1048 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1049
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001050 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001051}
1052
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001053/*
1054 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1055 * using ttrace->entry_time for a thread that receives a sys_exit without
1056 * first having received a sys_enter ("poll" issued before tracing session
1057 * starts, lost sys_enter exit due to ring buffer overflow).
1058 */
1059static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1060{
1061 if (tstamp > 0)
1062 return __trace__fprintf_tstamp(trace, tstamp, fp);
1063
1064 return fprintf(fp, " ? ");
1065}
1066
Namhyung Kimf15eb532012-10-05 14:02:16 +09001067static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001068static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001069
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001070static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001071{
1072 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001073 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001074}
1075
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001076static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001077 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001078{
1079 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001080 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001081
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001082 if (trace->multiple_threads) {
1083 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001084 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001085 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001086 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001087
1088 return printed;
1089}
1090
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001091static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001092 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001093{
1094 int ret = 0;
1095
1096 switch (event->header.type) {
1097 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001098 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001099 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001100 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001101 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001102 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001103 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104 break;
1105 }
1106
1107 return ret;
1108}
1109
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001110static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001112 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113 struct machine *machine)
1114{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001115 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001116 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001117}
1118
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001119static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1120{
1121 struct machine *machine = vmachine;
1122
1123 if (machine->kptr_restrict_warned)
1124 return NULL;
1125
1126 if (symbol_conf.kptr_restrict) {
1127 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1128 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1129 "Kernel samples will not be resolved.\n");
1130 machine->kptr_restrict_warned = true;
1131 return NULL;
1132 }
1133
1134 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1135}
1136
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1138{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001139 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001140
1141 if (err)
1142 return err;
1143
David Ahern8fb598e2013-09-28 13:13:00 -06001144 trace->host = machine__new_host();
1145 if (trace->host == NULL)
1146 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001147
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001148 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001149 return -errno;
1150
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001151 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001152 evlist->threads, trace__tool_process, false,
1153 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001154 if (err)
1155 symbol__exit();
1156
1157 return err;
1158}
1159
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001160static int syscall__set_arg_fmts(struct syscall *sc)
1161{
1162 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001163 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001164
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001165 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001166 if (sc->arg_scnprintf == NULL)
1167 return -1;
1168
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001169 if (sc->fmt)
1170 sc->arg_parm = sc->fmt->arg_parm;
1171
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001172 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001173 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1174 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001175 else if (strcmp(field->type, "const char *") == 0 &&
1176 (strcmp(field->name, "filename") == 0 ||
1177 strcmp(field->name, "path") == 0 ||
1178 strcmp(field->name, "pathname") == 0))
1179 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001180 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001181 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001182 else if (strcmp(field->type, "pid_t") == 0)
1183 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001184 else if (strcmp(field->type, "umode_t") == 0)
1185 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001186 else if ((strcmp(field->type, "int") == 0 ||
1187 strcmp(field->type, "unsigned int") == 0 ||
1188 strcmp(field->type, "long") == 0) &&
1189 (len = strlen(field->name)) >= 2 &&
1190 strcmp(field->name + len - 2, "fd") == 0) {
1191 /*
1192 * /sys/kernel/tracing/events/syscalls/sys_enter*
1193 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1194 * 65 int
1195 * 23 unsigned int
1196 * 7 unsigned long
1197 */
1198 sc->arg_scnprintf[idx] = SCA_FD;
1199 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001200 ++idx;
1201 }
1202
1203 return 0;
1204}
1205
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001206static int trace__read_syscall_info(struct trace *trace, int id)
1207{
1208 char tp_name[128];
1209 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001210 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001211
1212 if (name == NULL)
1213 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001214
1215 if (id > trace->syscalls.max) {
1216 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1217
1218 if (nsyscalls == NULL)
1219 return -1;
1220
1221 if (trace->syscalls.max != -1) {
1222 memset(nsyscalls + trace->syscalls.max + 1, 0,
1223 (id - trace->syscalls.max) * sizeof(*sc));
1224 } else {
1225 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1226 }
1227
1228 trace->syscalls.table = nsyscalls;
1229 trace->syscalls.max = id;
1230 }
1231
1232 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001233 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001234
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001235 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001236
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001237 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001238 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001239
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001240 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001241 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001242 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001243 }
1244
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001245 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001246 return -1;
1247
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001248 sc->args = sc->tp_format->format.fields;
1249 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001250 /*
1251 * We need to check and discard the first variable '__syscall_nr'
1252 * or 'nr' that mean the syscall number. It is needless here.
1253 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1254 */
1255 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001256 sc->args = sc->args->next;
1257 --sc->nr_args;
1258 }
1259
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001260 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1261
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001262 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001263}
1264
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001265static int trace__validate_ev_qualifier(struct trace *trace)
1266{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001267 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001268 struct str_node *pos;
1269
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001270 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1271 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1272 sizeof(trace->ev_qualifier_ids.entries[0]));
1273
1274 if (trace->ev_qualifier_ids.entries == NULL) {
1275 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1276 trace->output);
1277 err = -EINVAL;
1278 goto out;
1279 }
1280
1281 i = 0;
1282
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001283 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001284 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001285 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001286
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001287 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001288 if (err == 0) {
1289 fputs("Error:\tInvalid syscall ", trace->output);
1290 err = -EINVAL;
1291 } else {
1292 fputs(", ", trace->output);
1293 }
1294
1295 fputs(sc, trace->output);
1296 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001297
1298 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001299 }
1300
1301 if (err < 0) {
1302 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1303 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001304 zfree(&trace->ev_qualifier_ids.entries);
1305 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001306 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001307out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001308 return err;
1309}
1310
David Ahern55d43bc2015-02-19 15:00:22 -05001311/*
1312 * args is to be interpreted as a series of longs but we need to handle
1313 * 8-byte unaligned accesses. args points to raw_data within the event
1314 * and raw_data is guaranteed to be 8-byte unaligned because it is
1315 * preceded by raw_size which is a u32. So we need to copy args to a temp
1316 * variable to read it. Most notably this avoids extended load instructions
1317 * on unaligned addresses
1318 */
1319
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001320static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001321 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001322 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001323{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001324 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001325 unsigned char *p;
1326 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001327
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001328 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001329 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001330 u8 bit = 1;
1331 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001332 .idx = 0,
1333 .mask = 0,
1334 .trace = trace,
1335 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001336 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001337
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001338 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001339 field = field->next, ++arg.idx, bit <<= 1) {
1340 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001341 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001342
1343 /* special care for unaligned accesses */
1344 p = args + sizeof(unsigned long) * arg.idx;
1345 memcpy(&val, p, sizeof(val));
1346
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001347 /*
1348 * Suppress this argument if its value is zero and
1349 * and we don't have a string associated in an
1350 * strarray for it.
1351 */
David Ahern55d43bc2015-02-19 15:00:22 -05001352 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001353 !(sc->arg_scnprintf &&
1354 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1355 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001356 continue;
1357
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001358 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001359 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001360 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001361 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001362 if (sc->arg_parm)
1363 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001364 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1365 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001366 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001367 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001368 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001369 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001370 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001371 } else if (IS_ERR(sc->tp_format)) {
1372 /*
1373 * If we managed to read the tracepoint /format file, then we
1374 * may end up not having any args, like with gettid(), so only
1375 * print the raw args when we didn't manage to read it.
1376 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001377 int i = 0;
1378
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001379 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001380 /* special care for unaligned accesses */
1381 p = args + sizeof(unsigned long) * i;
1382 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001383 printed += scnprintf(bf + printed, size - printed,
1384 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001385 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386 ++i;
1387 }
1388 }
1389
1390 return printed;
1391}
1392
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001393typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001394 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001395 struct perf_sample *sample);
1396
1397static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001398 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001399{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001400
1401 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001402
1403 /*
1404 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1405 * before that, leaving at a higher verbosity level till that is
1406 * explained. Reproduced with plain ftrace with:
1407 *
1408 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1409 * grep "NR -1 " /t/trace_pipe
1410 *
1411 * After generating some load on the machine.
1412 */
1413 if (verbose > 1) {
1414 static u64 n;
1415 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1416 id, perf_evsel__name(evsel), ++n);
1417 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001418 return NULL;
1419 }
1420
1421 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1422 trace__read_syscall_info(trace, id))
1423 goto out_cant_read;
1424
1425 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1426 goto out_cant_read;
1427
1428 return &trace->syscalls.table[id];
1429
1430out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001431 if (verbose) {
1432 fprintf(trace->output, "Problems reading syscall %d", id);
1433 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1434 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1435 fputs(" information\n", trace->output);
1436 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001437 return NULL;
1438}
1439
David Ahernbf2575c2013-10-08 21:26:53 -06001440static void thread__update_stats(struct thread_trace *ttrace,
1441 int id, struct perf_sample *sample)
1442{
1443 struct int_node *inode;
1444 struct stats *stats;
1445 u64 duration = 0;
1446
1447 inode = intlist__findnew(ttrace->syscall_stats, id);
1448 if (inode == NULL)
1449 return;
1450
1451 stats = inode->priv;
1452 if (stats == NULL) {
1453 stats = malloc(sizeof(struct stats));
1454 if (stats == NULL)
1455 return;
1456 init_stats(stats);
1457 inode->priv = stats;
1458 }
1459
1460 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1461 duration = sample->time - ttrace->entry_time;
1462
1463 update_stats(stats, duration);
1464}
1465
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001466static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1467{
1468 struct thread_trace *ttrace;
1469 u64 duration;
1470 size_t printed;
1471
1472 if (trace->current == NULL)
1473 return 0;
1474
1475 ttrace = thread__priv(trace->current);
1476
1477 if (!ttrace->entry_pending)
1478 return 0;
1479
1480 duration = sample->time - ttrace->entry_time;
1481
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001482 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001483 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1484 ttrace->entry_pending = false;
1485
1486 return printed;
1487}
1488
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001489static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001490 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001491 struct perf_sample *sample)
1492{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001493 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001494 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001495 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001496 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001497 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001498 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001499 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001500
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001501 if (sc == NULL)
1502 return -1;
1503
David Ahern8fb598e2013-09-28 13:13:00 -06001504 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001505 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001506 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001507 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001508
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001509 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001510
1511 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001512 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001513 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001514 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001515 }
1516
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001517 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001518 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001519
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 ttrace->entry_time = sample->time;
1521 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001522 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001523
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001524 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001525 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001526
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001527 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001528 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001529 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001530 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001531 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001532 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001533 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001534 /* See trace__vfs_getname & trace__sys_exit */
1535 ttrace->filename.pending_open = false;
1536 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001537
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001538 if (trace->current != thread) {
1539 thread__put(trace->current);
1540 trace->current = thread__get(thread);
1541 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001542 err = 0;
1543out_put:
1544 thread__put(thread);
1545 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001546}
1547
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001548static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1549 struct perf_sample *sample,
1550 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001551{
1552 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001553
1554 if (machine__resolve(trace->host, &al, sample) < 0 ||
1555 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1556 return -1;
1557
1558 return 0;
1559}
1560
1561static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1562{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001563 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001564 const unsigned int print_opts = EVSEL__PRINT_SYM |
1565 EVSEL__PRINT_DSO |
1566 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001567
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001568 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001569}
1570
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001571static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001572 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001573 struct perf_sample *sample)
1574{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001575 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001576 u64 duration = 0;
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001577 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001578 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001579 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001580 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001581 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001582
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001583 if (sc == NULL)
1584 return -1;
1585
David Ahern8fb598e2013-09-28 13:13:00 -06001586 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001587 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001588 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001589 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001590
David Ahernbf2575c2013-10-08 21:26:53 -06001591 if (trace->summary)
1592 thread__update_stats(ttrace, id, sample);
1593
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001594 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001595
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001596 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001597 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1598 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001599 ++trace->stats.vfs_getname;
1600 }
1601
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001602 ttrace->exit_time = sample->time;
1603
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001604 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001605 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001606 if (trace__filter_duration(trace, duration))
1607 goto out;
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001608 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001609 } else if (trace->duration_filter)
1610 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001611
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001612 if (sample->callchain) {
1613 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1614 if (callchain_ret == 0) {
1615 if (callchain_cursor.nr < trace->min_stack)
1616 goto out;
1617 callchain_ret = 1;
1618 }
1619 }
1620
David Ahernfd2eaba2013-11-12 09:31:15 -07001621 if (trace->summary_only)
1622 goto out;
1623
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001624 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001625
1626 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001627 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001628 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001629 fprintf(trace->output, " ... [");
1630 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1631 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001632 }
1633
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001634 if (sc->fmt == NULL) {
1635signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001636 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001637 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001638 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001639 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001640 *e = audit_errno_to_name(-ret);
1641
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001642 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001643 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001644 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001645 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001646 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001647 else if (sc->fmt->errpid) {
1648 struct thread *child = machine__find_thread(trace->host, ret, ret);
1649
1650 if (child != NULL) {
1651 fprintf(trace->output, ") = %ld", ret);
1652 if (child->comm_set)
1653 fprintf(trace->output, " (%s)", thread__comm_str(child));
1654 thread__put(child);
1655 }
1656 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001657 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001658
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001659 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001660
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001661 if (callchain_ret > 0)
1662 trace__fprintf_callchain(trace, sample);
1663 else if (callchain_ret < 0)
1664 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001665out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001666 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001667 err = 0;
1668out_put:
1669 thread__put(thread);
1670 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001671}
1672
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001673static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001674 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001675 struct perf_sample *sample)
1676{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001677 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1678 struct thread_trace *ttrace;
1679 size_t filename_len, entry_str_len, to_move;
1680 ssize_t remaining_space;
1681 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001682 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001683
1684 if (!thread)
1685 goto out;
1686
1687 ttrace = thread__priv(thread);
1688 if (!ttrace)
1689 goto out;
1690
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001691 filename_len = strlen(filename);
1692
1693 if (ttrace->filename.namelen < filename_len) {
1694 char *f = realloc(ttrace->filename.name, filename_len + 1);
1695
1696 if (f == NULL)
1697 goto out;
1698
1699 ttrace->filename.namelen = filename_len;
1700 ttrace->filename.name = f;
1701 }
1702
1703 strcpy(ttrace->filename.name, filename);
1704 ttrace->filename.pending_open = true;
1705
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001706 if (!ttrace->filename.ptr)
1707 goto out;
1708
1709 entry_str_len = strlen(ttrace->entry_str);
1710 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1711 if (remaining_space <= 0)
1712 goto out;
1713
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001714 if (filename_len > (size_t)remaining_space) {
1715 filename += filename_len - remaining_space;
1716 filename_len = remaining_space;
1717 }
1718
1719 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1720 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1721 memmove(pos + filename_len, pos, to_move);
1722 memcpy(pos, filename, filename_len);
1723
1724 ttrace->filename.ptr = 0;
1725 ttrace->filename.entry_str_pos = 0;
1726out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001727 return 0;
1728}
1729
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001730static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001731 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001732 struct perf_sample *sample)
1733{
1734 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1735 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001736 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001737 sample->pid,
1738 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001739 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001740
1741 if (ttrace == NULL)
1742 goto out_dump;
1743
1744 ttrace->runtime_ms += runtime_ms;
1745 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001746 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001747 return 0;
1748
1749out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001750 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001751 evsel->name,
1752 perf_evsel__strval(evsel, sample, "comm"),
1753 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1754 runtime,
1755 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001756 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001757 return 0;
1758}
1759
Wang Nan1d6c9402016-02-26 09:31:55 +00001760static void bpf_output__printer(enum binary_printer_ops op,
1761 unsigned int val, void *extra)
1762{
1763 FILE *output = extra;
1764 unsigned char ch = (unsigned char)val;
1765
1766 switch (op) {
1767 case BINARY_PRINT_CHAR_DATA:
1768 fprintf(output, "%c", isprint(ch) ? ch : '.');
1769 break;
1770 case BINARY_PRINT_DATA_BEGIN:
1771 case BINARY_PRINT_LINE_BEGIN:
1772 case BINARY_PRINT_ADDR:
1773 case BINARY_PRINT_NUM_DATA:
1774 case BINARY_PRINT_NUM_PAD:
1775 case BINARY_PRINT_SEP:
1776 case BINARY_PRINT_CHAR_PAD:
1777 case BINARY_PRINT_LINE_END:
1778 case BINARY_PRINT_DATA_END:
1779 default:
1780 break;
1781 }
1782}
1783
1784static void bpf_output__fprintf(struct trace *trace,
1785 struct perf_sample *sample)
1786{
1787 print_binary(sample->raw_data, sample->raw_size, 8,
1788 bpf_output__printer, trace->output);
1789}
1790
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001791static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1792 union perf_event *event __maybe_unused,
1793 struct perf_sample *sample)
1794{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001795 int callchain_ret = 0;
1796
1797 if (sample->callchain) {
1798 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1799 if (callchain_ret == 0) {
1800 if (callchain_cursor.nr < trace->min_stack)
1801 goto out;
1802 callchain_ret = 1;
1803 }
1804 }
1805
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001806 trace__printf_interrupted_entry(trace, sample);
1807 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001808
1809 if (trace->trace_syscalls)
1810 fprintf(trace->output, "( ): ");
1811
1812 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001813
Wang Nan1d6c9402016-02-26 09:31:55 +00001814 if (perf_evsel__is_bpf_output(evsel)) {
1815 bpf_output__fprintf(trace, sample);
1816 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001817 event_format__fprintf(evsel->tp_format, sample->cpu,
1818 sample->raw_data, sample->raw_size,
1819 trace->output);
1820 }
1821
1822 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001823
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001824 if (callchain_ret > 0)
1825 trace__fprintf_callchain(trace, sample);
1826 else if (callchain_ret < 0)
1827 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1828out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001829 return 0;
1830}
1831
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001832static void print_location(FILE *f, struct perf_sample *sample,
1833 struct addr_location *al,
1834 bool print_dso, bool print_sym)
1835{
1836
1837 if ((verbose || print_dso) && al->map)
1838 fprintf(f, "%s@", al->map->dso->long_name);
1839
1840 if ((verbose || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001841 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001842 al->addr - al->sym->start);
1843 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001844 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001845 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001846 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001847}
1848
1849static int trace__pgfault(struct trace *trace,
1850 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001851 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001852 struct perf_sample *sample)
1853{
1854 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001855 struct addr_location al;
1856 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001857 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001858 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001859 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001860
1861 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001862
1863 if (sample->callchain) {
1864 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1865 if (callchain_ret == 0) {
1866 if (callchain_cursor.nr < trace->min_stack)
1867 goto out_put;
1868 callchain_ret = 1;
1869 }
1870 }
1871
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001872 ttrace = thread__trace(thread, trace->output);
1873 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001874 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001875
1876 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1877 ttrace->pfmaj++;
1878 else
1879 ttrace->pfmin++;
1880
1881 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001882 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001883
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001884 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001885 sample->ip, &al);
1886
Arnaldo Carvalho de Melo73f2c662017-03-29 16:37:51 -03001887 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888
1889 fprintf(trace->output, "%sfault [",
1890 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1891 "maj" : "min");
1892
1893 print_location(trace->output, sample, &al, false, true);
1894
1895 fprintf(trace->output, "] => ");
1896
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001897 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001898 sample->addr, &al);
1899
1900 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001901 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001902 MAP__FUNCTION, sample->addr, &al);
1903
1904 if (al.map)
1905 map_type = 'x';
1906 else
1907 map_type = '?';
1908 }
1909
1910 print_location(trace->output, sample, &al, true, false);
1911
1912 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001913
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001914 if (callchain_ret > 0)
1915 trace__fprintf_callchain(trace, sample);
1916 else if (callchain_ret < 0)
1917 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001918out:
1919 err = 0;
1920out_put:
1921 thread__put(thread);
1922 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001923}
1924
David Ahernbdc89662013-08-28 22:29:53 -06001925static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1926{
1927 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1928 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1929 return false;
1930
1931 if (trace->pid_list || trace->tid_list)
1932 return true;
1933
1934 return false;
1935}
1936
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001937static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001938 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001939 struct perf_sample *sample)
1940{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001941 /*
1942 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1943 * and don't use sample->time unconditionally, we may end up having
1944 * some other event in the future without PERF_SAMPLE_TIME for good
1945 * reason, i.e. we may not be interested in its timestamps, just in
1946 * it taking place, picking some piece of information when it
1947 * appears in our event stream (vfs_getname comes to mind).
1948 */
1949 if (trace->base_time == 0 && !trace->full_time &&
1950 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001951 trace->base_time = sample->time;
1952}
1953
David Ahern6810fc92013-08-28 22:29:52 -06001954static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001955 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001956 struct perf_sample *sample,
1957 struct perf_evsel *evsel,
1958 struct machine *machine __maybe_unused)
1959{
1960 struct trace *trace = container_of(tool, struct trace, tool);
1961 int err = 0;
1962
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001963 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001964
David Ahernbdc89662013-08-28 22:29:53 -06001965 if (skip_sample(trace, sample))
1966 return 0;
1967
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001968 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001969
David Ahern31605652013-12-04 19:41:41 -07001970 if (handler) {
1971 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001972 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001973 }
David Ahern6810fc92013-08-28 22:29:52 -06001974
1975 return err;
1976}
1977
David Ahernbdc89662013-08-28 22:29:53 -06001978static int parse_target_str(struct trace *trace)
1979{
1980 if (trace->opts.target.pid) {
1981 trace->pid_list = intlist__new(trace->opts.target.pid);
1982 if (trace->pid_list == NULL) {
1983 pr_err("Error parsing process id string\n");
1984 return -EINVAL;
1985 }
1986 }
1987
1988 if (trace->opts.target.tid) {
1989 trace->tid_list = intlist__new(trace->opts.target.tid);
1990 if (trace->tid_list == NULL) {
1991 pr_err("Error parsing thread id string\n");
1992 return -EINVAL;
1993 }
1994 }
1995
1996 return 0;
1997}
1998
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001999static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002000{
2001 unsigned int rec_argc, i, j;
2002 const char **rec_argv;
2003 const char * const record_args[] = {
2004 "record",
2005 "-R",
2006 "-m", "1024",
2007 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002008 };
2009
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002010 const char * const sc_args[] = { "-e", };
2011 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2012 const char * const majpf_args[] = { "-e", "major-faults" };
2013 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2014 const char * const minpf_args[] = { "-e", "minor-faults" };
2015 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2016
David Ahern9aca7f12013-12-04 19:41:39 -07002017 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002018 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2019 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002020 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2021
2022 if (rec_argv == NULL)
2023 return -ENOMEM;
2024
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002025 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002026 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002027 rec_argv[j++] = record_args[i];
2028
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002029 if (trace->trace_syscalls) {
2030 for (i = 0; i < sc_args_nr; i++)
2031 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002032
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002033 /* event string may be different for older kernels - e.g., RHEL6 */
2034 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2035 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2036 else if (is_valid_tracepoint("syscalls:sys_enter"))
2037 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2038 else {
2039 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2040 return -1;
2041 }
David Ahern9aca7f12013-12-04 19:41:39 -07002042 }
David Ahern9aca7f12013-12-04 19:41:39 -07002043
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002044 if (trace->trace_pgfaults & TRACE_PFMAJ)
2045 for (i = 0; i < majpf_args_nr; i++)
2046 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002047
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002048 if (trace->trace_pgfaults & TRACE_PFMIN)
2049 for (i = 0; i < minpf_args_nr; i++)
2050 rec_argv[j++] = minpf_args[i];
2051
2052 for (i = 0; i < (unsigned int)argc; i++)
2053 rec_argv[j++] = argv[i];
2054
2055 return cmd_record(j, rec_argv, NULL);
David Ahern5e2485b2013-09-28 13:13:01 -06002056}
2057
David Ahernbf2575c2013-10-08 21:26:53 -06002058static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2059
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002060static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002061{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002062 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002063
2064 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002065 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002066
2067 if (perf_evsel__field(evsel, "pathname") == NULL) {
2068 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002069 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002070 }
2071
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002072 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002073 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002074 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002075}
2076
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002077static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002078{
2079 struct perf_evsel *evsel;
2080 struct perf_event_attr attr = {
2081 .type = PERF_TYPE_SOFTWARE,
2082 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002083 };
2084
2085 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002086 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002087
2088 event_attr_init(&attr);
2089
2090 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002091 if (evsel)
2092 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002093
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002094 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002095}
2096
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002097static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2098{
2099 const u32 type = event->header.type;
2100 struct perf_evsel *evsel;
2101
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002102 if (type != PERF_RECORD_SAMPLE) {
2103 trace__process_event(trace, trace->host, event, sample);
2104 return;
2105 }
2106
2107 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2108 if (evsel == NULL) {
2109 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2110 return;
2111 }
2112
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002113 trace__set_base_time(trace, evsel, sample);
2114
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002115 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2116 sample->raw_data == NULL) {
2117 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2118 perf_evsel__name(evsel), sample->tid,
2119 sample->cpu, sample->raw_size);
2120 } else {
2121 tracepoint_handler handler = evsel->handler;
2122 handler(trace, evsel, event, sample);
2123 }
2124}
2125
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002126static int trace__add_syscall_newtp(struct trace *trace)
2127{
2128 int ret = -1;
2129 struct perf_evlist *evlist = trace->evlist;
2130 struct perf_evsel *sys_enter, *sys_exit;
2131
2132 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2133 if (sys_enter == NULL)
2134 goto out;
2135
2136 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2137 goto out_delete_sys_enter;
2138
2139 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2140 if (sys_exit == NULL)
2141 goto out_delete_sys_enter;
2142
2143 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2144 goto out_delete_sys_exit;
2145
2146 perf_evlist__add(evlist, sys_enter);
2147 perf_evlist__add(evlist, sys_exit);
2148
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002149 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002150 /*
2151 * We're interested only in the user space callchain
2152 * leading to the syscall, allow overriding that for
2153 * debugging reasons using --kernel_syscall_callchains
2154 */
2155 sys_exit->attr.exclude_callchain_kernel = 1;
2156 }
2157
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002158 trace->syscalls.events.sys_enter = sys_enter;
2159 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002160
2161 ret = 0;
2162out:
2163 return ret;
2164
2165out_delete_sys_exit:
2166 perf_evsel__delete_priv(sys_exit);
2167out_delete_sys_enter:
2168 perf_evsel__delete_priv(sys_enter);
2169 goto out;
2170}
2171
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002172static int trace__set_ev_qualifier_filter(struct trace *trace)
2173{
2174 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002175 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002176 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2177 trace->ev_qualifier_ids.nr,
2178 trace->ev_qualifier_ids.entries);
2179
2180 if (filter == NULL)
2181 goto out_enomem;
2182
Mathieu Poirier3541c032016-09-16 08:44:04 -06002183 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2184 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002185 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002186 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002187 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002188
2189 free(filter);
2190out:
2191 return err;
2192out_enomem:
2193 errno = ENOMEM;
2194 goto out;
2195}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002196
Namhyung Kimf15eb532012-10-05 14:02:16 +09002197static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002198{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002199 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002200 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002201 int err = -1, i;
2202 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002203 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002204 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002205
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002206 trace->live = true;
2207
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002208 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002209 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002210
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002211 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002212 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002213
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002214 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2215 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2216 if (pgfault_maj == NULL)
2217 goto out_error_mem;
2218 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002219 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002220
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002221 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2222 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2223 if (pgfault_min == NULL)
2224 goto out_error_mem;
2225 perf_evlist__add(evlist, pgfault_min);
2226 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002227
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002228 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002229 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2230 trace__sched_stat_runtime))
2231 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002232
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002233 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2234 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002235 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002236 goto out_delete_evlist;
2237 }
2238
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002239 err = trace__symbols_init(trace, evlist);
2240 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002241 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002242 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002243 }
2244
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002245 perf_evlist__config(evlist, &trace->opts, NULL);
2246
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002247 if (callchain_param.enabled) {
2248 bool use_identifier = false;
2249
2250 if (trace->syscalls.events.sys_exit) {
2251 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2252 &trace->opts, &callchain_param);
2253 use_identifier = true;
2254 }
2255
2256 if (pgfault_maj) {
2257 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2258 use_identifier = true;
2259 }
2260
2261 if (pgfault_min) {
2262 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2263 use_identifier = true;
2264 }
2265
2266 if (use_identifier) {
2267 /*
2268 * Now we have evsels with different sample_ids, use
2269 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2270 * from a fixed position in each ring buffer record.
2271 *
2272 * As of this the changeset introducing this comment, this
2273 * isn't strictly needed, as the fields that can come before
2274 * PERF_SAMPLE_ID are all used, but we'll probably disable
2275 * some of those for things like copying the payload of
2276 * pointer syscall arguments, and for vfs_getname we don't
2277 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2278 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2279 */
2280 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2281 perf_evlist__reset_sample_bit(evlist, ID);
2282 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002283 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002284
Namhyung Kimf15eb532012-10-05 14:02:16 +09002285 signal(SIGCHLD, sig_handler);
2286 signal(SIGINT, sig_handler);
2287
2288 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002289 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002290 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002291 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002292 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002293 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002294 }
2295 }
2296
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002297 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002298 if (err < 0)
2299 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002300
Wang Nanba504232016-02-26 09:31:54 +00002301 err = bpf__apply_obj_config();
2302 if (err) {
2303 char errbuf[BUFSIZ];
2304
2305 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2306 pr_err("ERROR: Apply config to BPF failed: %s\n",
2307 errbuf);
2308 goto out_error_open;
2309 }
2310
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002311 /*
2312 * Better not use !target__has_task() here because we need to cover the
2313 * case where no threads were specified in the command line, but a
2314 * workload was, and in that case we will fill in the thread_map when
2315 * we fork the workload in perf_evlist__prepare_workload.
2316 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002317 if (trace->filter_pids.nr > 0)
2318 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002319 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002320 err = perf_evlist__set_filter_pid(evlist, getpid());
2321
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002322 if (err < 0)
2323 goto out_error_mem;
2324
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002325 if (trace->ev_qualifier_ids.nr > 0) {
2326 err = trace__set_ev_qualifier_filter(trace);
2327 if (err < 0)
2328 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002329
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002330 pr_debug("event qualifier tracepoint filter: %s\n",
2331 trace->syscalls.events.sys_exit->filter);
2332 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002333
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002334 err = perf_evlist__apply_filters(evlist, &evsel);
2335 if (err < 0)
2336 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002337
Jiri Olsaf8850372013-11-28 17:57:22 +01002338 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002339 if (err < 0)
2340 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002341
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002342 if (!target__none(&trace->opts.target))
2343 perf_evlist__enable(evlist);
2344
Namhyung Kimf15eb532012-10-05 14:02:16 +09002345 if (forks)
2346 perf_evlist__start_workload(evlist);
2347
Jiri Olsae13798c2015-06-23 00:36:02 +02002348 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002349 evlist->threads->nr > 1 ||
2350 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002351again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002352 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002353
2354 for (i = 0; i < evlist->nr_mmaps; i++) {
2355 union perf_event *event;
2356
2357 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002358 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002359
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002360 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002361
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002362 err = perf_evlist__parse_sample(evlist, event, &sample);
2363 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002364 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002365 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002366 }
2367
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002368 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002369next_event:
2370 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002371
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002372 if (interrupted)
2373 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002374
2375 if (done && !draining) {
2376 perf_evlist__disable(evlist);
2377 draining = true;
2378 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002379 }
2380 }
2381
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002382 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002383 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002384
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002385 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2386 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2387 draining = true;
2388
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002389 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002390 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002391 } else {
2392 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002393 }
2394
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002395out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002396 thread__zput(trace->current);
2397
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002398 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002399
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002400 if (!err) {
2401 if (trace->summary)
2402 trace__fprintf_thread_summary(trace, trace->output);
2403
2404 if (trace->show_tool_stats) {
2405 fprintf(trace->output, "Stats:\n "
2406 " vfs_getname : %" PRIu64 "\n"
2407 " proc_getname: %" PRIu64 "\n",
2408 trace->stats.vfs_getname,
2409 trace->stats.proc_getname);
2410 }
2411 }
David Ahernbf2575c2013-10-08 21:26:53 -06002412
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002413out_delete_evlist:
2414 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002415 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002416 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002417 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002418{
2419 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002420
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002421out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002422 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002423 goto out_error;
2424
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002425out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002426 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002427 goto out_error;
2428
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002429out_error_mmap:
2430 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2431 goto out_error;
2432
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002433out_error_open:
2434 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2435
2436out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002437 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302438 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002439
2440out_error_apply_filters:
2441 fprintf(trace->output,
2442 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2443 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002444 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002445 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002446}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002447out_error_mem:
2448 fprintf(trace->output, "Not enough memory to run!\n");
2449 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002450
2451out_errno:
2452 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2453 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002454}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002455
David Ahern6810fc92013-08-28 22:29:52 -06002456static int trace__replay(struct trace *trace)
2457{
2458 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002459 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002460 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002461 struct perf_data_file file = {
2462 .path = input_name,
2463 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002464 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002465 };
David Ahern6810fc92013-08-28 22:29:52 -06002466 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002467 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002468 int err = -1;
2469
2470 trace->tool.sample = trace__process_sample;
2471 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002472 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002473 trace->tool.comm = perf_event__process_comm;
2474 trace->tool.exit = perf_event__process_exit;
2475 trace->tool.fork = perf_event__process_fork;
2476 trace->tool.attr = perf_event__process_attr;
2477 trace->tool.tracing_data = perf_event__process_tracing_data;
2478 trace->tool.build_id = perf_event__process_build_id;
2479
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002480 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002481 trace->tool.ordering_requires_timestamps = true;
2482
2483 /* add tid to output */
2484 trace->multiple_threads = true;
2485
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002486 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002487 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002488 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002489
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002490 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002491 goto out;
2492
David Ahern8fb598e2013-09-28 13:13:00 -06002493 trace->host = &session->machines.host;
2494
David Ahern6810fc92013-08-28 22:29:52 -06002495 err = perf_session__set_tracepoints_handlers(session, handlers);
2496 if (err)
2497 goto out;
2498
Namhyung Kim003824e2013-11-12 15:25:00 +09002499 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2500 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002501 /* older kernels have syscalls tp versus raw_syscalls */
2502 if (evsel == NULL)
2503 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2504 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002505
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002506 if (evsel &&
2507 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2508 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002509 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2510 goto out;
2511 }
2512
2513 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2514 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002515 if (evsel == NULL)
2516 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2517 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002518 if (evsel &&
2519 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2520 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002521 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002522 goto out;
2523 }
2524
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002525 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002526 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2527 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2528 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2529 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2530 evsel->handler = trace__pgfault;
2531 }
2532
David Ahernbdc89662013-08-28 22:29:53 -06002533 err = parse_target_str(trace);
2534 if (err != 0)
2535 goto out;
2536
David Ahern6810fc92013-08-28 22:29:52 -06002537 setup_pager();
2538
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002539 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002540 if (err)
2541 pr_err("Failed to process events, error %d", err);
2542
David Ahernbf2575c2013-10-08 21:26:53 -06002543 else if (trace->summary)
2544 trace__fprintf_thread_summary(trace, trace->output);
2545
David Ahern6810fc92013-08-28 22:29:52 -06002546out:
2547 perf_session__delete(session);
2548
2549 return err;
2550}
2551
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002552static size_t trace__fprintf_threads_header(FILE *fp)
2553{
2554 size_t printed;
2555
Pekka Enberg99ff7152013-11-12 16:42:14 +02002556 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002557
2558 return printed;
2559}
2560
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002561DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2562 struct stats *stats;
2563 double msecs;
2564 int syscall;
2565)
2566{
2567 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2568 struct stats *stats = source->priv;
2569
2570 entry->syscall = source->i;
2571 entry->stats = stats;
2572 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2573}
2574
David Ahernbf2575c2013-10-08 21:26:53 -06002575static size_t thread__dump_stats(struct thread_trace *ttrace,
2576 struct trace *trace, FILE *fp)
2577{
David Ahernbf2575c2013-10-08 21:26:53 -06002578 size_t printed = 0;
2579 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002580 struct rb_node *nd;
2581 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002582
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002583 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002584 return 0;
2585
2586 printed += fprintf(fp, "\n");
2587
Milian Wolff834fd462015-08-06 11:24:29 +02002588 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2589 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2590 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002591
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002592 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002593 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002594 if (stats) {
2595 double min = (double)(stats->min) / NSEC_PER_MSEC;
2596 double max = (double)(stats->max) / NSEC_PER_MSEC;
2597 double avg = avg_stats(stats);
2598 double pct;
2599 u64 n = (u64) stats->n;
2600
2601 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2602 avg /= NSEC_PER_MSEC;
2603
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002604 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002605 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002606 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002607 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002608 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002609 }
David Ahernbf2575c2013-10-08 21:26:53 -06002610 }
2611
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002612 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002613 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002614
2615 return printed;
2616}
2617
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002618static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002619{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002620 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002621 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002622 double ratio;
2623
2624 if (ttrace == NULL)
2625 return 0;
2626
2627 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2628
Pekka Enberg15e65c62013-11-14 18:43:30 +02002629 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002630 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002631 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002632 if (ttrace->pfmaj)
2633 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2634 if (ttrace->pfmin)
2635 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002636 if (trace->sched)
2637 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2638 else if (fputc('\n', fp) != EOF)
2639 ++printed;
2640
David Ahernbf2575c2013-10-08 21:26:53 -06002641 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002642
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002643 return printed;
2644}
David Ahern896cbb52013-09-28 13:12:59 -06002645
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002646static unsigned long thread__nr_events(struct thread_trace *ttrace)
2647{
2648 return ttrace ? ttrace->nr_events : 0;
2649}
2650
2651DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2652 struct thread *thread;
2653)
2654{
2655 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002656}
2657
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002658static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2659{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002660 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2661 size_t printed = trace__fprintf_threads_header(fp);
2662 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002663
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002664 if (threads == NULL) {
2665 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2666 return 0;
2667 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002668
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002669 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002670 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2671
2672 resort_rb__delete(threads);
2673
2674 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002675}
2676
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002677static int trace__set_duration(const struct option *opt, const char *str,
2678 int unset __maybe_unused)
2679{
2680 struct trace *trace = opt->value;
2681
2682 trace->duration_filter = atof(str);
2683 return 0;
2684}
2685
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002686static int trace__set_filter_pids(const struct option *opt, const char *str,
2687 int unset __maybe_unused)
2688{
2689 int ret = -1;
2690 size_t i;
2691 struct trace *trace = opt->value;
2692 /*
2693 * FIXME: introduce a intarray class, plain parse csv and create a
2694 * { int nr, int entries[] } struct...
2695 */
2696 struct intlist *list = intlist__new(str);
2697
2698 if (list == NULL)
2699 return -1;
2700
2701 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2702 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2703
2704 if (trace->filter_pids.entries == NULL)
2705 goto out;
2706
2707 trace->filter_pids.entries[0] = getpid();
2708
2709 for (i = 1; i < trace->filter_pids.nr; ++i)
2710 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2711
2712 intlist__delete(list);
2713 ret = 0;
2714out:
2715 return ret;
2716}
2717
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002718static int trace__open_output(struct trace *trace, const char *filename)
2719{
2720 struct stat st;
2721
2722 if (!stat(filename, &st) && st.st_size) {
2723 char oldname[PATH_MAX];
2724
2725 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2726 unlink(oldname);
2727 rename(filename, oldname);
2728 }
2729
2730 trace->output = fopen(filename, "w");
2731
2732 return trace->output == NULL ? -errno : 0;
2733}
2734
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002735static int parse_pagefaults(const struct option *opt, const char *str,
2736 int unset __maybe_unused)
2737{
2738 int *trace_pgfaults = opt->value;
2739
2740 if (strcmp(str, "all") == 0)
2741 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2742 else if (strcmp(str, "maj") == 0)
2743 *trace_pgfaults |= TRACE_PFMAJ;
2744 else if (strcmp(str, "min") == 0)
2745 *trace_pgfaults |= TRACE_PFMIN;
2746 else
2747 return -1;
2748
2749 return 0;
2750}
2751
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002752static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2753{
2754 struct perf_evsel *evsel;
2755
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002756 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002757 evsel->handler = handler;
2758}
2759
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002760int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2761{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002762 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002763 "perf trace [<options>] [<command>]",
2764 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002765 "perf trace record [<options>] [<command>]",
2766 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002767 NULL
2768 };
2769 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002770 .syscalls = {
2771 . max = -1,
2772 },
2773 .opts = {
2774 .target = {
2775 .uid = UINT_MAX,
2776 .uses_mmap = true,
2777 },
2778 .user_freq = UINT_MAX,
2779 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002780 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002781 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002782 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002783 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002784 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002785 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002786 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002787 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002788 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002789 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002790 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002791 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002792 const struct option trace_options[] = {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002793 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2794 "event selector. use 'perf list' to list available events",
2795 parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002796 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2797 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002798 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melod303e852015-04-23 12:02:07 -03002799 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002800 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002801 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002802 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2803 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002804 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002805 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002806 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2807 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002808 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002809 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002810 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002811 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002812 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002813 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002814 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2815 "number of mmap data pages",
2816 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002817 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002818 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002819 OPT_CALLBACK(0, "duration", &trace, "float",
2820 "show only events with duration > N.M ms",
2821 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002822 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002823 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002824 OPT_BOOLEAN('T', "time", &trace.full_time,
2825 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002826 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2827 "Show only syscall summary with statistics"),
2828 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2829 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002830 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2831 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002832 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002833 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002834 OPT_CALLBACK(0, "call-graph", &trace.opts,
2835 "record_mode[,record_size]", record_callchain_help,
2836 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002837 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2838 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002839 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2840 "Set the minimum stack depth when parsing the callchain, "
2841 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002842 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2843 "Set the maximum stack depth when parsing the callchain, "
2844 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002845 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002846 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2847 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002848 OPT_END()
2849 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002850 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002851 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002852 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002853 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002854 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002855
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002856 signal(SIGSEGV, sighandler_dump_stack);
2857 signal(SIGFPE, sighandler_dump_stack);
2858
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002859 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002860 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002861
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002862 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002863 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002864 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002865 goto out;
2866 }
2867
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002868 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2869 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002870
Wang Nand7888572016-04-08 15:07:24 +00002871 err = bpf__setup_stdout(trace.evlist);
2872 if (err) {
2873 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2874 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2875 goto out;
2876 }
2877
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002878 err = -1;
2879
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002880 if (trace.trace_pgfaults) {
2881 trace.opts.sample_address = true;
2882 trace.opts.sample_time = true;
2883 }
2884
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002885 if (trace.opts.mmap_pages == UINT_MAX)
2886 mmap_pages_user_set = false;
2887
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002888 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002889 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002890 max_stack_user_set = false;
2891 }
2892
2893#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002894 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002895 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2896#endif
2897
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002898 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002899 if (!mmap_pages_user_set && geteuid() == 0)
2900 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2901
Milian Wolff566a0882016-04-08 13:34:15 +02002902 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002903 }
Milian Wolff566a0882016-04-08 13:34:15 +02002904
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002905 if (trace.evlist->nr_entries > 0)
2906 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2907
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002908 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2909 return trace__record(&trace, argc-1, &argv[1]);
2910
2911 /* summary_only implies summary option, but don't overwrite summary if set */
2912 if (trace.summary_only)
2913 trace.summary = trace.summary_only;
2914
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002915 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2916 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002917 pr_err("Please specify something to trace.\n");
2918 return -1;
2919 }
2920
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002921 if (!trace.trace_syscalls && ev_qualifier_str) {
2922 pr_err("The -e option can't be used with --no-syscalls.\n");
2923 goto out;
2924 }
2925
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002926 if (output_name != NULL) {
2927 err = trace__open_output(&trace, output_name);
2928 if (err < 0) {
2929 perror("failed to create output file");
2930 goto out;
2931 }
2932 }
2933
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002934 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2935
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002936 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002937 const char *s = ev_qualifier_str;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002938 struct strlist_config slist_config = {
2939 .dirname = system_path(STRACE_GROUPS_DIR),
2940 };
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03002941
2942 trace.not_ev_qualifier = *s == '!';
2943 if (trace.not_ev_qualifier)
2944 ++s;
Arnaldo Carvalho de Melo005438a2015-07-20 12:02:09 -03002945 trace.ev_qualifier = strlist__new(s, &slist_config);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002946 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002947 fputs("Not enough memory to parse event qualifier",
2948 trace.output);
2949 err = -ENOMEM;
2950 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002951 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03002952
2953 err = trace__validate_ev_qualifier(&trace);
2954 if (err)
2955 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03002956 }
2957
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002958 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002959 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002960 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002961 fprintf(trace.output, "%s", bf);
2962 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002963 }
2964
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002965 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002966 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002967 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002968 fprintf(trace.output, "%s", bf);
2969 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002970 }
2971
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002972 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002973 trace.opts.target.system_wide = true;
2974
David Ahern6810fc92013-08-28 22:29:52 -06002975 if (input_name)
2976 err = trace__replay(&trace);
2977 else
2978 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002979
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002980out_close:
2981 if (output_name != NULL)
2982 fclose(trace.output);
2983out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002984 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002985}