blob: aba5fac4152923faf50e6be2e1723ad98964b3e9 [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"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030034#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010035#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070036#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000037#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020038#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030039#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030040#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030041
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030042#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030043#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030044#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030045#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020046#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030047#include <linux/filter.h>
48#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030049#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030050#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030051#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030052#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030053
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030054#ifndef O_CLOEXEC
55# define O_CLOEXEC 02000000
56#endif
57
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030058struct trace {
59 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030060 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030061 struct {
62 int max;
63 struct syscall *table;
64 struct {
65 struct perf_evsel *sys_enter,
66 *sys_exit;
67 } events;
68 } syscalls;
69 struct record_opts opts;
70 struct perf_evlist *evlist;
71 struct machine *host;
72 struct thread *current;
73 u64 base_time;
74 FILE *output;
75 unsigned long nr_events;
76 struct strlist *ev_qualifier;
77 struct {
78 size_t nr;
79 int *entries;
80 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030081 struct {
82 size_t nr;
83 pid_t *entries;
84 } filter_pids;
85 double duration_filter;
86 double runtime_ms;
87 struct {
88 u64 vfs_getname,
89 proc_getname;
90 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030091 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030092 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030093 bool not_ev_qualifier;
94 bool live;
95 bool full_time;
96 bool sched;
97 bool multiple_threads;
98 bool summary;
99 bool summary_only;
100 bool show_comm;
101 bool show_tool_stats;
102 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300103 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300104 bool force;
105 bool vfs_getname;
106 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300107 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300108};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300109
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300110struct tp_field {
111 int offset;
112 union {
113 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
114 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
115 };
116};
117
118#define TP_UINT_FIELD(bits) \
119static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
120{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500121 u##bits value; \
122 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
123 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300124}
125
126TP_UINT_FIELD(8);
127TP_UINT_FIELD(16);
128TP_UINT_FIELD(32);
129TP_UINT_FIELD(64);
130
131#define TP_UINT_FIELD__SWAPPED(bits) \
132static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
133{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500134 u##bits value; \
135 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300136 return bswap_##bits(value);\
137}
138
139TP_UINT_FIELD__SWAPPED(16);
140TP_UINT_FIELD__SWAPPED(32);
141TP_UINT_FIELD__SWAPPED(64);
142
143static int tp_field__init_uint(struct tp_field *field,
144 struct format_field *format_field,
145 bool needs_swap)
146{
147 field->offset = format_field->offset;
148
149 switch (format_field->size) {
150 case 1:
151 field->integer = tp_field__u8;
152 break;
153 case 2:
154 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
155 break;
156 case 4:
157 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
158 break;
159 case 8:
160 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
161 break;
162 default:
163 return -1;
164 }
165
166 return 0;
167}
168
169static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
170{
171 return sample->raw_data + field->offset;
172}
173
174static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
175{
176 field->offset = format_field->offset;
177 field->pointer = tp_field__ptr;
178 return 0;
179}
180
181struct syscall_tp {
182 struct tp_field id;
183 union {
184 struct tp_field args, ret;
185 };
186};
187
188static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
189 struct tp_field *field,
190 const char *name)
191{
192 struct format_field *format_field = perf_evsel__field(evsel, name);
193
194 if (format_field == NULL)
195 return -1;
196
197 return tp_field__init_uint(field, format_field, evsel->needs_swap);
198}
199
200#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
201 ({ struct syscall_tp *sc = evsel->priv;\
202 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
203
204static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
205 struct tp_field *field,
206 const char *name)
207{
208 struct format_field *format_field = perf_evsel__field(evsel, name);
209
210 if (format_field == NULL)
211 return -1;
212
213 return tp_field__init_ptr(field, format_field);
214}
215
216#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
217 ({ struct syscall_tp *sc = evsel->priv;\
218 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
219
220static void perf_evsel__delete_priv(struct perf_evsel *evsel)
221{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300222 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300223 perf_evsel__delete(evsel);
224}
225
Namhyung Kim96695d42013-11-12 08:51:45 -0300226static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
227{
228 evsel->priv = malloc(sizeof(struct syscall_tp));
229 if (evsel->priv != NULL) {
230 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
231 goto out_delete;
232
233 evsel->handler = handler;
234 return 0;
235 }
236
237 return -ENOMEM;
238
239out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300240 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300241 return -ENOENT;
242}
243
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300244static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300245{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300246 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300247
David Ahern9aca7f12013-12-04 19:41:39 -0700248 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200249 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700250 evsel = perf_evsel__newtp("syscalls", direction);
251
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200252 if (IS_ERR(evsel))
253 return NULL;
254
255 if (perf_evsel__init_syscall_tp(evsel, handler))
256 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300257
258 return evsel;
259
260out_delete:
261 perf_evsel__delete_priv(evsel);
262 return NULL;
263}
264
265#define perf_evsel__sc_tp_uint(evsel, name, sample) \
266 ({ struct syscall_tp *fields = evsel->priv; \
267 fields->name.integer(&fields->name, sample); })
268
269#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
270 ({ struct syscall_tp *fields = evsel->priv; \
271 fields->name.pointer(&fields->name, sample); })
272
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300273struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300274 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300275 int nr_entries;
276 const char **entries;
277};
278
279#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
280 .nr_entries = ARRAY_SIZE(array), \
281 .entries = array, \
282}
283
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300284#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
285 .offset = off, \
286 .nr_entries = ARRAY_SIZE(array), \
287 .entries = array, \
288}
289
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300290static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
291 const char *intfmt,
292 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300293{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300294 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300295 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300296
297 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300298 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299
300 return scnprintf(bf, size, "%s", sa->entries[idx]);
301}
302
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
307}
308
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309#define SCA_STRARRAY syscall_arg__scnprintf_strarray
310
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300311#if defined(__i386__) || defined(__x86_64__)
312/*
313 * FIXME: Make this available to all arches as soon as the ioctl beautifier
314 * gets rewritten to support all arches.
315 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300316static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
317 struct syscall_arg *arg)
318{
319 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
320}
321
322#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300323#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300324
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300325static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
326 struct syscall_arg *arg);
327
328#define SCA_FD syscall_arg__scnprintf_fd
329
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300330#ifndef AT_FDCWD
331#define AT_FDCWD -100
332#endif
333
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300334static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
335 struct syscall_arg *arg)
336{
337 int fd = arg->val;
338
339 if (fd == AT_FDCWD)
340 return scnprintf(bf, size, "CWD");
341
342 return syscall_arg__scnprintf_fd(bf, size, arg);
343}
344
345#define SCA_FDAT syscall_arg__scnprintf_fd_at
346
347static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
348 struct syscall_arg *arg);
349
350#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
351
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300352static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300353 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300354{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300355 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300356}
357
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300358#define SCA_HEX syscall_arg__scnprintf_hex
359
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300360static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
361 struct syscall_arg *arg)
362{
363 return scnprintf(bf, size, "%d", arg->val);
364}
365
366#define SCA_INT syscall_arg__scnprintf_int
367
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300368static const char *bpf_cmd[] = {
369 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
370 "MAP_GET_NEXT_KEY", "PROG_LOAD",
371};
372static DEFINE_STRARRAY(bpf_cmd);
373
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300374static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
375static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300376
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300377static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
378static DEFINE_STRARRAY(itimers);
379
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300380static const char *keyctl_options[] = {
381 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
382 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
383 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
384 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
385 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
386};
387static DEFINE_STRARRAY(keyctl_options);
388
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300389static const char *whences[] = { "SET", "CUR", "END",
390#ifdef SEEK_DATA
391"DATA",
392#endif
393#ifdef SEEK_HOLE
394"HOLE",
395#endif
396};
397static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300398
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300399static const char *fcntl_cmds[] = {
400 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
401 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
402 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
403 "F_GETOWNER_UIDS",
404};
405static DEFINE_STRARRAY(fcntl_cmds);
406
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300407static const char *rlimit_resources[] = {
408 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
409 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
410 "RTTIME",
411};
412static DEFINE_STRARRAY(rlimit_resources);
413
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300414static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
415static DEFINE_STRARRAY(sighow);
416
David Ahern4f8c1b72013-09-22 19:45:00 -0600417static const char *clockid[] = {
418 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300419 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
420 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600421};
422static DEFINE_STRARRAY(clockid);
423
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300424static const char *socket_families[] = {
425 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
426 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
427 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
428 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
429 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
430 "ALG", "NFC", "VSOCK",
431};
432static DEFINE_STRARRAY(socket_families);
433
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300434static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
435 struct syscall_arg *arg)
436{
437 size_t printed = 0;
438 int mode = arg->val;
439
440 if (mode == F_OK) /* 0 */
441 return scnprintf(bf, size, "F");
442#define P_MODE(n) \
443 if (mode & n##_OK) { \
444 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
445 mode &= ~n##_OK; \
446 }
447
448 P_MODE(R);
449 P_MODE(W);
450 P_MODE(X);
451#undef P_MODE
452
453 if (mode)
454 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
455
456 return printed;
457}
458
459#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
460
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300461static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
462 struct syscall_arg *arg);
463
464#define SCA_FILENAME syscall_arg__scnprintf_filename
465
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300466static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
467 struct syscall_arg *arg)
468{
469 int printed = 0, flags = arg->val;
470
471#define P_FLAG(n) \
472 if (flags & O_##n) { \
473 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
474 flags &= ~O_##n; \
475 }
476
477 P_FLAG(CLOEXEC);
478 P_FLAG(NONBLOCK);
479#undef P_FLAG
480
481 if (flags)
482 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
483
484 return printed;
485}
486
487#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
488
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300489#if defined(__i386__) || defined(__x86_64__)
490/*
491 * FIXME: Make this available to all arches.
492 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300493#define TCGETS 0x5401
494
495static const char *tioctls[] = {
496 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
497 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
498 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
499 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
500 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
501 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
502 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
503 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
504 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
505 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
506 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
507 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
508 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
509 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
510 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
511};
512
513static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300514#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300515
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300516#ifndef GRND_NONBLOCK
517#define GRND_NONBLOCK 0x0001
518#endif
519#ifndef GRND_RANDOM
520#define GRND_RANDOM 0x0002
521#endif
522
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300523static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
524 struct syscall_arg *arg)
525{
526 int printed = 0, flags = arg->val;
527
528#define P_FLAG(n) \
529 if (flags & GRND_##n) { \
530 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
531 flags &= ~GRND_##n; \
532 }
533
534 P_FLAG(RANDOM);
535 P_FLAG(NONBLOCK);
536#undef P_FLAG
537
538 if (flags)
539 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
540
541 return printed;
542}
543
544#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
545
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300546#define STRARRAY(arg, name, array) \
547 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
548 .arg_parm = { [arg] = &strarray__##array, }
549
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300550#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300551#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300552#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300553#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300554#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300555#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300556#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300557#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300558#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300559#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300560#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300561#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300562#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300563#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300564
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300565static struct syscall_fmt {
566 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300567 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300568 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300569 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300570 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300571 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300572 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300573 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300574} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300575 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300576 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300577 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300578 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300579 { .name = "brk", .hexret = true,
580 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300581 { .name = "chdir", .errmsg = true, },
582 { .name = "chmod", .errmsg = true, },
583 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600584 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300585 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300586 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300587 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300588 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300589 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300590 { .name = "dup", .errmsg = true, },
591 { .name = "dup2", .errmsg = true, },
592 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300593 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300594 { .name = "eventfd2", .errmsg = true,
595 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300596 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300597 { .name = "fadvise64", .errmsg = true, },
598 { .name = "fallocate", .errmsg = true, },
599 { .name = "fchdir", .errmsg = true, },
600 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300601 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300602 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300603 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300604 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300605 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300606 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300607 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300608 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300609 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300610 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300611 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
612 { .name = "fsetxattr", .errmsg = true, },
613 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300614 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300615 { .name = "fstatfs", .errmsg = true, },
616 { .name = "fsync", .errmsg = true, },
617 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300618 { .name = "futex", .errmsg = true,
619 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300620 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300621 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300622 { .name = "getdents", .errmsg = true, },
623 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300624 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300625 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300626 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300627 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300628 { .name = "getrandom", .errmsg = true,
629 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300630 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300631 { .name = "getxattr", .errmsg = true, },
632 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300633 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300634 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300635#if defined(__i386__) || defined(__x86_64__)
636/*
637 * FIXME: Make this available to all arches.
638 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300639 [1] = SCA_STRHEXARRAY, /* cmd */
640 [2] = SCA_HEX, /* arg */ },
641 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300642#else
643 [2] = SCA_HEX, /* arg */ }, },
644#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300645 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300646 { .name = "kill", .errmsg = true,
647 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300648 { .name = "lchown", .errmsg = true, },
649 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300650 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300651 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300652 { .name = "listxattr", .errmsg = true, },
653 { .name = "llistxattr", .errmsg = true, },
654 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300655 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300656 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300657 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300658 { .name = "lsetxattr", .errmsg = true, },
659 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
660 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300661 { .name = "madvise", .errmsg = true,
662 .arg_scnprintf = { [0] = SCA_HEX, /* start */
663 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300664 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300665 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300666 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
667 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300668 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300669 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300670 { .name = "mlock", .errmsg = true,
671 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
672 { .name = "mlockall", .errmsg = true,
673 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300674 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300675 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300676 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300677 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300678 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300679 .arg_scnprintf = { [0] = SCA_HEX, /* start */
680 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300681 { .name = "mq_unlink", .errmsg = true,
682 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300683 { .name = "mremap", .hexret = true,
684 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300685 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300686 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300687 { .name = "munlock", .errmsg = true,
688 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300689 { .name = "munmap", .errmsg = true,
690 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300691 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300692 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300693 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300694 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300695 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300696 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300697 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300698 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
699 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300700 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300701 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
702 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300703 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300704 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300705 [3] = SCA_FD, /* group_fd */
706 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300707 { .name = "pipe2", .errmsg = true,
708 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300709 { .name = "poll", .errmsg = true, .timeout = true, },
710 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300711 { .name = "pread", .errmsg = true, .alias = "pread64", },
712 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300713 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300714 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
715 { .name = "pwritev", .errmsg = true, },
716 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300717 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300718 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300719 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300720 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300721 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300722 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300723 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300724 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300725 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300726 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300727 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300728 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300729 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300730 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300731 { .name = "rt_sigaction", .errmsg = true,
732 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300733 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300734 { .name = "rt_sigqueueinfo", .errmsg = true,
735 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
736 { .name = "rt_tgsigqueueinfo", .errmsg = true,
737 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300738 { .name = "sched_getattr", .errmsg = true, },
739 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300740 { .name = "sched_setscheduler", .errmsg = true,
741 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300742 { .name = "seccomp", .errmsg = true,
743 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
744 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300745 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300746 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300747 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300748 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300749 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300750 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300751 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300752 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300753 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300754 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300755 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300756 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300757 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300758 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300759 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
760 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300761 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300762 { .name = "socketpair", .errmsg = true,
763 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
764 [1] = SCA_SK_TYPE, /* type */ },
765 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300766 { .name = "stat", .errmsg = true, .alias = "newstat", },
767 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300768 { .name = "statx", .errmsg = true,
769 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
770 [2] = SCA_STATX_FLAGS, /* flags */
771 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300772 { .name = "swapoff", .errmsg = true,
773 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
774 { .name = "swapon", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300776 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300777 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300778 { .name = "tgkill", .errmsg = true,
779 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
780 { .name = "tkill", .errmsg = true,
781 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300782 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300783 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300784 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300785 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
786 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300787 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300788 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
789 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300790 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300791 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300792 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300793 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300794 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300795 { .name = "write", .errmsg = true, },
796 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300797};
798
799static int syscall_fmt__cmp(const void *name, const void *fmtp)
800{
801 const struct syscall_fmt *fmt = fmtp;
802 return strcmp(name, fmt->name);
803}
804
805static struct syscall_fmt *syscall_fmt__find(const char *name)
806{
807 const int nmemb = ARRAY_SIZE(syscall_fmts);
808 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
809}
810
811struct syscall {
812 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300813 int nr_args;
814 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300815 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300816 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300818 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300819 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300820};
821
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300822/*
823 * We need to have this 'calculated' boolean because in some cases we really
824 * don't know what is the duration of a syscall, for instance, when we start
825 * a session and some threads are waiting for a syscall to finish, say 'poll',
826 * in which case all we can do is to print "( ? ) for duration and for the
827 * start timestamp.
828 */
829static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200830{
831 double duration = (double)t / NSEC_PER_MSEC;
832 size_t printed = fprintf(fp, "(");
833
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300834 if (!calculated)
835 printed += fprintf(fp, " ? ");
836 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200837 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
838 else if (duration >= 0.01)
839 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
840 else
841 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300842 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200843}
844
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300845/**
846 * filename.ptr: The filename char pointer that will be vfs_getname'd
847 * filename.entry_str_pos: Where to insert the string translated from
848 * filename.ptr by the vfs_getname tracepoint/kprobe.
849 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300850struct thread_trace {
851 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300852 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300853 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400854 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300855 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300856 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300857 struct {
858 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300859 short int entry_str_pos;
860 bool pending_open;
861 unsigned int namelen;
862 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300863 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300864 struct {
865 int max;
866 char **table;
867 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600868
869 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300870};
871
872static struct thread_trace *thread_trace__new(void)
873{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300874 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
875
876 if (ttrace)
877 ttrace->paths.max = -1;
878
David Ahernbf2575c2013-10-08 21:26:53 -0600879 ttrace->syscall_stats = intlist__new(NULL);
880
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300881 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300882}
883
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300884static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300885{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300886 struct thread_trace *ttrace;
887
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300888 if (thread == NULL)
889 goto fail;
890
Namhyung Kim89dceb22014-10-06 09:46:03 +0900891 if (thread__priv(thread) == NULL)
892 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300893
Namhyung Kim89dceb22014-10-06 09:46:03 +0900894 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895 goto fail;
896
Namhyung Kim89dceb22014-10-06 09:46:03 +0900897 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300898 ++ttrace->nr_events;
899
900 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300901fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300902 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300903 "WARNING: not enough memory, dropping samples!\n");
904 return NULL;
905}
906
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400907#define TRACE_PFMAJ (1 << 0)
908#define TRACE_PFMIN (1 << 1)
909
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300910static const size_t trace__entry_str_size = 2048;
911
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300912static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300913{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900914 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300915
916 if (fd > ttrace->paths.max) {
917 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
918
919 if (npath == NULL)
920 return -1;
921
922 if (ttrace->paths.max != -1) {
923 memset(npath + ttrace->paths.max + 1, 0,
924 (fd - ttrace->paths.max) * sizeof(char *));
925 } else {
926 memset(npath, 0, (fd + 1) * sizeof(char *));
927 }
928
929 ttrace->paths.table = npath;
930 ttrace->paths.max = fd;
931 }
932
933 ttrace->paths.table[fd] = strdup(pathname);
934
935 return ttrace->paths.table[fd] != NULL ? 0 : -1;
936}
937
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300938static int thread__read_fd_path(struct thread *thread, int fd)
939{
940 char linkname[PATH_MAX], pathname[PATH_MAX];
941 struct stat st;
942 int ret;
943
944 if (thread->pid_ == thread->tid) {
945 scnprintf(linkname, sizeof(linkname),
946 "/proc/%d/fd/%d", thread->pid_, fd);
947 } else {
948 scnprintf(linkname, sizeof(linkname),
949 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
950 }
951
952 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
953 return -1;
954
955 ret = readlink(linkname, pathname, sizeof(pathname));
956
957 if (ret < 0 || ret > st.st_size)
958 return -1;
959
960 pathname[ret] = '\0';
961 return trace__set_fd_pathname(thread, fd, pathname);
962}
963
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300964static const char *thread__fd_path(struct thread *thread, int fd,
965 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300966{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900967 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300968
969 if (ttrace == NULL)
970 return NULL;
971
972 if (fd < 0)
973 return NULL;
974
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300975 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300976 if (!trace->live)
977 return NULL;
978 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300979 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300980 return NULL;
981 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982
983 return ttrace->paths.table[fd];
984}
985
986static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
987 struct syscall_arg *arg)
988{
989 int fd = arg->val;
990 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300991 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300992
993 if (path)
994 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
995
996 return printed;
997}
998
999static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1000 struct syscall_arg *arg)
1001{
1002 int fd = arg->val;
1003 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001004 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001005
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001006 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1007 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001008
1009 return printed;
1010}
1011
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001012static void thread__set_filename_pos(struct thread *thread, const char *bf,
1013 unsigned long ptr)
1014{
1015 struct thread_trace *ttrace = thread__priv(thread);
1016
1017 ttrace->filename.ptr = ptr;
1018 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1019}
1020
1021static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1022 struct syscall_arg *arg)
1023{
1024 unsigned long ptr = arg->val;
1025
1026 if (!arg->trace->vfs_getname)
1027 return scnprintf(bf, size, "%#x", ptr);
1028
1029 thread__set_filename_pos(arg->thread, bf, ptr);
1030 return 0;
1031}
1032
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001033static bool trace__filter_duration(struct trace *trace, double t)
1034{
1035 return t < (trace->duration_filter * NSEC_PER_MSEC);
1036}
1037
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001038static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001039{
1040 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1041
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001042 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001043}
1044
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001045/*
1046 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1047 * using ttrace->entry_time for a thread that receives a sys_exit without
1048 * first having received a sys_enter ("poll" issued before tracing session
1049 * starts, lost sys_enter exit due to ring buffer overflow).
1050 */
1051static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1052{
1053 if (tstamp > 0)
1054 return __trace__fprintf_tstamp(trace, tstamp, fp);
1055
1056 return fprintf(fp, " ? ");
1057}
1058
Namhyung Kimf15eb532012-10-05 14:02:16 +09001059static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001060static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001061
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001062static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001063{
1064 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001065 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001066}
1067
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001068static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001069 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001070{
1071 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001072 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001073
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001074 if (trace->multiple_threads) {
1075 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001076 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001077 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001078 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001079
1080 return printed;
1081}
1082
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001083static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001084 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001085{
1086 int ret = 0;
1087
1088 switch (event->header.type) {
1089 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001090 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001091 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001092 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001093 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001095 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096 break;
1097 }
1098
1099 return ret;
1100}
1101
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001102static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001103 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001104 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105 struct machine *machine)
1106{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001107 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001108 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109}
1110
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001111static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1112{
1113 struct machine *machine = vmachine;
1114
1115 if (machine->kptr_restrict_warned)
1116 return NULL;
1117
1118 if (symbol_conf.kptr_restrict) {
1119 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1120 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1121 "Kernel samples will not be resolved.\n");
1122 machine->kptr_restrict_warned = true;
1123 return NULL;
1124 }
1125
1126 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1127}
1128
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001129static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1130{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001131 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001132
1133 if (err)
1134 return err;
1135
David Ahern8fb598e2013-09-28 13:13:00 -06001136 trace->host = machine__new_host();
1137 if (trace->host == NULL)
1138 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001139
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001140 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001141 return -errno;
1142
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001143 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001144 evlist->threads, trace__tool_process, false,
1145 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 if (err)
1147 symbol__exit();
1148
1149 return err;
1150}
1151
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001152static int syscall__set_arg_fmts(struct syscall *sc)
1153{
1154 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001155 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001156
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001157 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001158 if (sc->arg_scnprintf == NULL)
1159 return -1;
1160
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001161 if (sc->fmt)
1162 sc->arg_parm = sc->fmt->arg_parm;
1163
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001164 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001165 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1166 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001167 else if (strcmp(field->type, "const char *") == 0 &&
1168 (strcmp(field->name, "filename") == 0 ||
1169 strcmp(field->name, "path") == 0 ||
1170 strcmp(field->name, "pathname") == 0))
1171 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001172 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001173 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001174 else if (strcmp(field->type, "pid_t") == 0)
1175 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001176 else if (strcmp(field->type, "umode_t") == 0)
1177 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001178 else if ((strcmp(field->type, "int") == 0 ||
1179 strcmp(field->type, "unsigned int") == 0 ||
1180 strcmp(field->type, "long") == 0) &&
1181 (len = strlen(field->name)) >= 2 &&
1182 strcmp(field->name + len - 2, "fd") == 0) {
1183 /*
1184 * /sys/kernel/tracing/events/syscalls/sys_enter*
1185 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1186 * 65 int
1187 * 23 unsigned int
1188 * 7 unsigned long
1189 */
1190 sc->arg_scnprintf[idx] = SCA_FD;
1191 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001192 ++idx;
1193 }
1194
1195 return 0;
1196}
1197
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001198static int trace__read_syscall_info(struct trace *trace, int id)
1199{
1200 char tp_name[128];
1201 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001202 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001203
1204 if (name == NULL)
1205 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001206
1207 if (id > trace->syscalls.max) {
1208 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1209
1210 if (nsyscalls == NULL)
1211 return -1;
1212
1213 if (trace->syscalls.max != -1) {
1214 memset(nsyscalls + trace->syscalls.max + 1, 0,
1215 (id - trace->syscalls.max) * sizeof(*sc));
1216 } else {
1217 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1218 }
1219
1220 trace->syscalls.table = nsyscalls;
1221 trace->syscalls.max = id;
1222 }
1223
1224 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001225 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001226
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001227 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001228
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001229 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001230 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001231
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001232 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001233 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001234 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001235 }
1236
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001237 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001238 return -1;
1239
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001240 sc->args = sc->tp_format->format.fields;
1241 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001242 /*
1243 * We need to check and discard the first variable '__syscall_nr'
1244 * or 'nr' that mean the syscall number. It is needless here.
1245 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1246 */
1247 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001248 sc->args = sc->args->next;
1249 --sc->nr_args;
1250 }
1251
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001252 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1253
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001254 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001255}
1256
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001257static int trace__validate_ev_qualifier(struct trace *trace)
1258{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001259 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001260 struct str_node *pos;
1261
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001262 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1263 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1264 sizeof(trace->ev_qualifier_ids.entries[0]));
1265
1266 if (trace->ev_qualifier_ids.entries == NULL) {
1267 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1268 trace->output);
1269 err = -EINVAL;
1270 goto out;
1271 }
1272
1273 i = 0;
1274
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001275 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001276 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001277 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001278
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001279 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001280 if (err == 0) {
1281 fputs("Error:\tInvalid syscall ", trace->output);
1282 err = -EINVAL;
1283 } else {
1284 fputs(", ", trace->output);
1285 }
1286
1287 fputs(sc, trace->output);
1288 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001289
1290 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001291 }
1292
1293 if (err < 0) {
1294 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1295 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001296 zfree(&trace->ev_qualifier_ids.entries);
1297 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001298 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001299out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001300 return err;
1301}
1302
David Ahern55d43bca2015-02-19 15:00:22 -05001303/*
1304 * args is to be interpreted as a series of longs but we need to handle
1305 * 8-byte unaligned accesses. args points to raw_data within the event
1306 * and raw_data is guaranteed to be 8-byte unaligned because it is
1307 * preceded by raw_size which is a u32. So we need to copy args to a temp
1308 * variable to read it. Most notably this avoids extended load instructions
1309 * on unaligned addresses
1310 */
1311
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001312static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001313 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001314 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001315{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001316 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001317 unsigned char *p;
1318 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001319
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001320 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001322 u8 bit = 1;
1323 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001324 .idx = 0,
1325 .mask = 0,
1326 .trace = trace,
1327 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001328 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001329
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001330 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001331 field = field->next, ++arg.idx, bit <<= 1) {
1332 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001333 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001334
1335 /* special care for unaligned accesses */
1336 p = args + sizeof(unsigned long) * arg.idx;
1337 memcpy(&val, p, sizeof(val));
1338
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001339 /*
1340 * Suppress this argument if its value is zero and
1341 * and we don't have a string associated in an
1342 * strarray for it.
1343 */
David Ahern55d43bca2015-02-19 15:00:22 -05001344 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001345 !(sc->arg_scnprintf &&
1346 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1347 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001348 continue;
1349
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001350 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001351 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001352 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001353 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001354 if (sc->arg_parm)
1355 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001356 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1357 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001358 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001359 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001360 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001361 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001362 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001363 } else if (IS_ERR(sc->tp_format)) {
1364 /*
1365 * If we managed to read the tracepoint /format file, then we
1366 * may end up not having any args, like with gettid(), so only
1367 * print the raw args when we didn't manage to read it.
1368 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001369 int i = 0;
1370
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001372 /* special care for unaligned accesses */
1373 p = args + sizeof(unsigned long) * i;
1374 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001375 printed += scnprintf(bf + printed, size - printed,
1376 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001377 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001378 ++i;
1379 }
1380 }
1381
1382 return printed;
1383}
1384
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001385typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001386 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001387 struct perf_sample *sample);
1388
1389static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001390 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001391{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001392
1393 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001394
1395 /*
1396 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1397 * before that, leaving at a higher verbosity level till that is
1398 * explained. Reproduced with plain ftrace with:
1399 *
1400 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1401 * grep "NR -1 " /t/trace_pipe
1402 *
1403 * After generating some load on the machine.
1404 */
1405 if (verbose > 1) {
1406 static u64 n;
1407 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1408 id, perf_evsel__name(evsel), ++n);
1409 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001410 return NULL;
1411 }
1412
1413 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1414 trace__read_syscall_info(trace, id))
1415 goto out_cant_read;
1416
1417 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1418 goto out_cant_read;
1419
1420 return &trace->syscalls.table[id];
1421
1422out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001423 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001424 fprintf(trace->output, "Problems reading syscall %d", id);
1425 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1426 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1427 fputs(" information\n", trace->output);
1428 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001429 return NULL;
1430}
1431
David Ahernbf2575c2013-10-08 21:26:53 -06001432static void thread__update_stats(struct thread_trace *ttrace,
1433 int id, struct perf_sample *sample)
1434{
1435 struct int_node *inode;
1436 struct stats *stats;
1437 u64 duration = 0;
1438
1439 inode = intlist__findnew(ttrace->syscall_stats, id);
1440 if (inode == NULL)
1441 return;
1442
1443 stats = inode->priv;
1444 if (stats == NULL) {
1445 stats = malloc(sizeof(struct stats));
1446 if (stats == NULL)
1447 return;
1448 init_stats(stats);
1449 inode->priv = stats;
1450 }
1451
1452 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1453 duration = sample->time - ttrace->entry_time;
1454
1455 update_stats(stats, duration);
1456}
1457
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001458static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1459{
1460 struct thread_trace *ttrace;
1461 u64 duration;
1462 size_t printed;
1463
1464 if (trace->current == NULL)
1465 return 0;
1466
1467 ttrace = thread__priv(trace->current);
1468
1469 if (!ttrace->entry_pending)
1470 return 0;
1471
1472 duration = sample->time - ttrace->entry_time;
1473
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001474 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001475 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1476 ttrace->entry_pending = false;
1477
1478 return printed;
1479}
1480
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001481static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001482 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001483 struct perf_sample *sample)
1484{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001485 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001486 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001488 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001489 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001490 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001491 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001492
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001493 if (sc == NULL)
1494 return -1;
1495
David Ahern8fb598e2013-09-28 13:13:00 -06001496 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001497 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001498 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001499 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001500
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001501 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001502
1503 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001504 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001505 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001506 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001507 }
1508
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001509 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001510 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001511
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001512 ttrace->entry_time = sample->time;
1513 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001514 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001515
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001516 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001517 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001518
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001519 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001520 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001521 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001522 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001523 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001524 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001525 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001526 /* See trace__vfs_getname & trace__sys_exit */
1527 ttrace->filename.pending_open = false;
1528 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001529
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001530 if (trace->current != thread) {
1531 thread__put(trace->current);
1532 trace->current = thread__get(thread);
1533 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001534 err = 0;
1535out_put:
1536 thread__put(thread);
1537 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001538}
1539
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001540static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1541 struct perf_sample *sample,
1542 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001543{
1544 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001545
1546 if (machine__resolve(trace->host, &al, sample) < 0 ||
1547 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1548 return -1;
1549
1550 return 0;
1551}
1552
1553static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1554{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001555 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001556 const unsigned int print_opts = EVSEL__PRINT_SYM |
1557 EVSEL__PRINT_DSO |
1558 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001559
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001560 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001561}
1562
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001563static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001564 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001565 struct perf_sample *sample)
1566{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001567 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001568 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001569 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001570 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001571 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001572 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001573 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001574
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001575 if (sc == NULL)
1576 return -1;
1577
David Ahern8fb598e2013-09-28 13:13:00 -06001578 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001579 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001580 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001581 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001582
David Ahernbf2575c2013-10-08 21:26:53 -06001583 if (trace->summary)
1584 thread__update_stats(ttrace, id, sample);
1585
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001586 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001587
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001588 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001589 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1590 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001591 ++trace->stats.vfs_getname;
1592 }
1593
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001594 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001595 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001596 if (trace__filter_duration(trace, duration))
1597 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001598 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001599 } else if (trace->duration_filter)
1600 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001601
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001602 if (sample->callchain) {
1603 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1604 if (callchain_ret == 0) {
1605 if (callchain_cursor.nr < trace->min_stack)
1606 goto out;
1607 callchain_ret = 1;
1608 }
1609 }
1610
David Ahernfd2eaba2013-11-12 09:31:15 -07001611 if (trace->summary_only)
1612 goto out;
1613
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001614 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001615
1616 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001617 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001618 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001619 fprintf(trace->output, " ... [");
1620 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1621 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001622 }
1623
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001624 if (sc->fmt == NULL) {
1625signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001626 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001627 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001628 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001629 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001630 *e = audit_errno_to_name(-ret);
1631
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001632 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001633 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001634 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001635 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001636 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001637 else if (sc->fmt->errpid) {
1638 struct thread *child = machine__find_thread(trace->host, ret, ret);
1639
1640 if (child != NULL) {
1641 fprintf(trace->output, ") = %ld", ret);
1642 if (child->comm_set)
1643 fprintf(trace->output, " (%s)", thread__comm_str(child));
1644 thread__put(child);
1645 }
1646 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001647 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001648
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001649 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001650
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001651 if (callchain_ret > 0)
1652 trace__fprintf_callchain(trace, sample);
1653 else if (callchain_ret < 0)
1654 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001655out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001656 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001657 err = 0;
1658out_put:
1659 thread__put(thread);
1660 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001661}
1662
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001663static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001664 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001665 struct perf_sample *sample)
1666{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001667 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1668 struct thread_trace *ttrace;
1669 size_t filename_len, entry_str_len, to_move;
1670 ssize_t remaining_space;
1671 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001672 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001673
1674 if (!thread)
1675 goto out;
1676
1677 ttrace = thread__priv(thread);
1678 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001679 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001680
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001681 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001682 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001683 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001684
1685 if (ttrace->filename.namelen < filename_len) {
1686 char *f = realloc(ttrace->filename.name, filename_len + 1);
1687
1688 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001689 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001690
1691 ttrace->filename.namelen = filename_len;
1692 ttrace->filename.name = f;
1693 }
1694
1695 strcpy(ttrace->filename.name, filename);
1696 ttrace->filename.pending_open = true;
1697
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001698 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001699 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001700
1701 entry_str_len = strlen(ttrace->entry_str);
1702 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1703 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001704 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001705
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001706 if (filename_len > (size_t)remaining_space) {
1707 filename += filename_len - remaining_space;
1708 filename_len = remaining_space;
1709 }
1710
1711 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1712 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1713 memmove(pos + filename_len, pos, to_move);
1714 memcpy(pos, filename, filename_len);
1715
1716 ttrace->filename.ptr = 0;
1717 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001718out_put:
1719 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001720out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001721 return 0;
1722}
1723
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001724static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001725 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001726 struct perf_sample *sample)
1727{
1728 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1729 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001730 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001731 sample->pid,
1732 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001733 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001734
1735 if (ttrace == NULL)
1736 goto out_dump;
1737
1738 ttrace->runtime_ms += runtime_ms;
1739 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001740out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001741 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001742 return 0;
1743
1744out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001745 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001746 evsel->name,
1747 perf_evsel__strval(evsel, sample, "comm"),
1748 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1749 runtime,
1750 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001751 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001752}
1753
Wang Nan1d6c9402016-02-26 09:31:55 +00001754static void bpf_output__printer(enum binary_printer_ops op,
1755 unsigned int val, void *extra)
1756{
1757 FILE *output = extra;
1758 unsigned char ch = (unsigned char)val;
1759
1760 switch (op) {
1761 case BINARY_PRINT_CHAR_DATA:
1762 fprintf(output, "%c", isprint(ch) ? ch : '.');
1763 break;
1764 case BINARY_PRINT_DATA_BEGIN:
1765 case BINARY_PRINT_LINE_BEGIN:
1766 case BINARY_PRINT_ADDR:
1767 case BINARY_PRINT_NUM_DATA:
1768 case BINARY_PRINT_NUM_PAD:
1769 case BINARY_PRINT_SEP:
1770 case BINARY_PRINT_CHAR_PAD:
1771 case BINARY_PRINT_LINE_END:
1772 case BINARY_PRINT_DATA_END:
1773 default:
1774 break;
1775 }
1776}
1777
1778static void bpf_output__fprintf(struct trace *trace,
1779 struct perf_sample *sample)
1780{
1781 print_binary(sample->raw_data, sample->raw_size, 8,
1782 bpf_output__printer, trace->output);
1783}
1784
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001785static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1786 union perf_event *event __maybe_unused,
1787 struct perf_sample *sample)
1788{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001789 int callchain_ret = 0;
1790
1791 if (sample->callchain) {
1792 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1793 if (callchain_ret == 0) {
1794 if (callchain_cursor.nr < trace->min_stack)
1795 goto out;
1796 callchain_ret = 1;
1797 }
1798 }
1799
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001800 trace__printf_interrupted_entry(trace, sample);
1801 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001802
1803 if (trace->trace_syscalls)
1804 fprintf(trace->output, "( ): ");
1805
1806 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001807
Wang Nan1d6c9402016-02-26 09:31:55 +00001808 if (perf_evsel__is_bpf_output(evsel)) {
1809 bpf_output__fprintf(trace, sample);
1810 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001811 event_format__fprintf(evsel->tp_format, sample->cpu,
1812 sample->raw_data, sample->raw_size,
1813 trace->output);
1814 }
1815
1816 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001817
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001818 if (callchain_ret > 0)
1819 trace__fprintf_callchain(trace, sample);
1820 else if (callchain_ret < 0)
1821 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1822out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001823 return 0;
1824}
1825
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001826static void print_location(FILE *f, struct perf_sample *sample,
1827 struct addr_location *al,
1828 bool print_dso, bool print_sym)
1829{
1830
Namhyung Kimbb963e12017-02-17 17:17:38 +09001831 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001832 fprintf(f, "%s@", al->map->dso->long_name);
1833
Namhyung Kimbb963e12017-02-17 17:17:38 +09001834 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001835 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001836 al->addr - al->sym->start);
1837 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001838 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001839 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001840 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001841}
1842
1843static int trace__pgfault(struct trace *trace,
1844 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001845 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001846 struct perf_sample *sample)
1847{
1848 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001849 struct addr_location al;
1850 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001851 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001852 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001853 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001854
1855 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001856
1857 if (sample->callchain) {
1858 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1859 if (callchain_ret == 0) {
1860 if (callchain_cursor.nr < trace->min_stack)
1861 goto out_put;
1862 callchain_ret = 1;
1863 }
1864 }
1865
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001866 ttrace = thread__trace(thread, trace->output);
1867 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001868 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001869
1870 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1871 ttrace->pfmaj++;
1872 else
1873 ttrace->pfmin++;
1874
1875 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001876 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001877
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001878 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001879 sample->ip, &al);
1880
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001881 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001882
1883 fprintf(trace->output, "%sfault [",
1884 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1885 "maj" : "min");
1886
1887 print_location(trace->output, sample, &al, false, true);
1888
1889 fprintf(trace->output, "] => ");
1890
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001891 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001892 sample->addr, &al);
1893
1894 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001895 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001896 MAP__FUNCTION, sample->addr, &al);
1897
1898 if (al.map)
1899 map_type = 'x';
1900 else
1901 map_type = '?';
1902 }
1903
1904 print_location(trace->output, sample, &al, true, false);
1905
1906 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001907
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001908 if (callchain_ret > 0)
1909 trace__fprintf_callchain(trace, sample);
1910 else if (callchain_ret < 0)
1911 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001912out:
1913 err = 0;
1914out_put:
1915 thread__put(thread);
1916 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001917}
1918
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001919static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001920 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001921 struct perf_sample *sample)
1922{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001923 /*
1924 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1925 * and don't use sample->time unconditionally, we may end up having
1926 * some other event in the future without PERF_SAMPLE_TIME for good
1927 * reason, i.e. we may not be interested in its timestamps, just in
1928 * it taking place, picking some piece of information when it
1929 * appears in our event stream (vfs_getname comes to mind).
1930 */
1931 if (trace->base_time == 0 && !trace->full_time &&
1932 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001933 trace->base_time = sample->time;
1934}
1935
David Ahern6810fc92013-08-28 22:29:52 -06001936static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001937 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001938 struct perf_sample *sample,
1939 struct perf_evsel *evsel,
1940 struct machine *machine __maybe_unused)
1941{
1942 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001943 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001944 int err = 0;
1945
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001946 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001947
David Ahernaa07df62016-11-25 09:29:52 -07001948 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1949 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001950 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06001951
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001952 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001953
David Ahern31605652013-12-04 19:41:41 -07001954 if (handler) {
1955 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001956 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001957 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001958out:
1959 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06001960 return err;
1961}
1962
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001963static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001964{
1965 unsigned int rec_argc, i, j;
1966 const char **rec_argv;
1967 const char * const record_args[] = {
1968 "record",
1969 "-R",
1970 "-m", "1024",
1971 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001972 };
1973
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001974 const char * const sc_args[] = { "-e", };
1975 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1976 const char * const majpf_args[] = { "-e", "major-faults" };
1977 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1978 const char * const minpf_args[] = { "-e", "minor-faults" };
1979 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1980
David Ahern9aca7f12013-12-04 19:41:39 -07001981 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001982 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1983 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001984 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1985
1986 if (rec_argv == NULL)
1987 return -ENOMEM;
1988
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001989 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001990 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001991 rec_argv[j++] = record_args[i];
1992
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001993 if (trace->trace_syscalls) {
1994 for (i = 0; i < sc_args_nr; i++)
1995 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001996
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001997 /* event string may be different for older kernels - e.g., RHEL6 */
1998 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
1999 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2000 else if (is_valid_tracepoint("syscalls:sys_enter"))
2001 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2002 else {
2003 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2004 return -1;
2005 }
David Ahern9aca7f12013-12-04 19:41:39 -07002006 }
David Ahern9aca7f12013-12-04 19:41:39 -07002007
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002008 if (trace->trace_pgfaults & TRACE_PFMAJ)
2009 for (i = 0; i < majpf_args_nr; i++)
2010 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002011
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002012 if (trace->trace_pgfaults & TRACE_PFMIN)
2013 for (i = 0; i < minpf_args_nr; i++)
2014 rec_argv[j++] = minpf_args[i];
2015
2016 for (i = 0; i < (unsigned int)argc; i++)
2017 rec_argv[j++] = argv[i];
2018
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002019 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002020}
2021
David Ahernbf2575c2013-10-08 21:26:53 -06002022static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2023
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002024static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002025{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002026 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002027
2028 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002029 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002030
2031 if (perf_evsel__field(evsel, "pathname") == NULL) {
2032 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002033 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002034 }
2035
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002036 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002037 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002038 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002039}
2040
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002041static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002042{
2043 struct perf_evsel *evsel;
2044 struct perf_event_attr attr = {
2045 .type = PERF_TYPE_SOFTWARE,
2046 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002047 };
2048
2049 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002050 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002051
2052 event_attr_init(&attr);
2053
2054 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002055 if (evsel)
2056 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002057
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002058 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002059}
2060
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002061static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2062{
2063 const u32 type = event->header.type;
2064 struct perf_evsel *evsel;
2065
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002066 if (type != PERF_RECORD_SAMPLE) {
2067 trace__process_event(trace, trace->host, event, sample);
2068 return;
2069 }
2070
2071 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2072 if (evsel == NULL) {
2073 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2074 return;
2075 }
2076
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002077 trace__set_base_time(trace, evsel, sample);
2078
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002079 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2080 sample->raw_data == NULL) {
2081 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2082 perf_evsel__name(evsel), sample->tid,
2083 sample->cpu, sample->raw_size);
2084 } else {
2085 tracepoint_handler handler = evsel->handler;
2086 handler(trace, evsel, event, sample);
2087 }
2088}
2089
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002090static int trace__add_syscall_newtp(struct trace *trace)
2091{
2092 int ret = -1;
2093 struct perf_evlist *evlist = trace->evlist;
2094 struct perf_evsel *sys_enter, *sys_exit;
2095
2096 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2097 if (sys_enter == NULL)
2098 goto out;
2099
2100 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2101 goto out_delete_sys_enter;
2102
2103 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2104 if (sys_exit == NULL)
2105 goto out_delete_sys_enter;
2106
2107 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2108 goto out_delete_sys_exit;
2109
2110 perf_evlist__add(evlist, sys_enter);
2111 perf_evlist__add(evlist, sys_exit);
2112
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002113 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002114 /*
2115 * We're interested only in the user space callchain
2116 * leading to the syscall, allow overriding that for
2117 * debugging reasons using --kernel_syscall_callchains
2118 */
2119 sys_exit->attr.exclude_callchain_kernel = 1;
2120 }
2121
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002122 trace->syscalls.events.sys_enter = sys_enter;
2123 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002124
2125 ret = 0;
2126out:
2127 return ret;
2128
2129out_delete_sys_exit:
2130 perf_evsel__delete_priv(sys_exit);
2131out_delete_sys_enter:
2132 perf_evsel__delete_priv(sys_enter);
2133 goto out;
2134}
2135
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002136static int trace__set_ev_qualifier_filter(struct trace *trace)
2137{
2138 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002139 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002140 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2141 trace->ev_qualifier_ids.nr,
2142 trace->ev_qualifier_ids.entries);
2143
2144 if (filter == NULL)
2145 goto out_enomem;
2146
Mathieu Poirier3541c032016-09-16 08:44:04 -06002147 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2148 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002149 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002150 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002151 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002152
2153 free(filter);
2154out:
2155 return err;
2156out_enomem:
2157 errno = ENOMEM;
2158 goto out;
2159}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002160
Namhyung Kimf15eb532012-10-05 14:02:16 +09002161static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002162{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002163 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002164 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002165 int err = -1, i;
2166 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002167 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002168 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002169
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002170 trace->live = true;
2171
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002172 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002173 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002174
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002175 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002176 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002177
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002178 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2179 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2180 if (pgfault_maj == NULL)
2181 goto out_error_mem;
2182 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002183 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002184
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002185 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2186 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2187 if (pgfault_min == NULL)
2188 goto out_error_mem;
2189 perf_evlist__add(evlist, pgfault_min);
2190 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002191
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002192 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002193 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2194 trace__sched_stat_runtime))
2195 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002196
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002197 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2198 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002199 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002200 goto out_delete_evlist;
2201 }
2202
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002203 err = trace__symbols_init(trace, evlist);
2204 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002205 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002206 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002207 }
2208
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002209 perf_evlist__config(evlist, &trace->opts, NULL);
2210
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002211 if (callchain_param.enabled) {
2212 bool use_identifier = false;
2213
2214 if (trace->syscalls.events.sys_exit) {
2215 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2216 &trace->opts, &callchain_param);
2217 use_identifier = true;
2218 }
2219
2220 if (pgfault_maj) {
2221 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2222 use_identifier = true;
2223 }
2224
2225 if (pgfault_min) {
2226 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2227 use_identifier = true;
2228 }
2229
2230 if (use_identifier) {
2231 /*
2232 * Now we have evsels with different sample_ids, use
2233 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2234 * from a fixed position in each ring buffer record.
2235 *
2236 * As of this the changeset introducing this comment, this
2237 * isn't strictly needed, as the fields that can come before
2238 * PERF_SAMPLE_ID are all used, but we'll probably disable
2239 * some of those for things like copying the payload of
2240 * pointer syscall arguments, and for vfs_getname we don't
2241 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2242 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2243 */
2244 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2245 perf_evlist__reset_sample_bit(evlist, ID);
2246 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002247 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002248
Namhyung Kimf15eb532012-10-05 14:02:16 +09002249 signal(SIGCHLD, sig_handler);
2250 signal(SIGINT, sig_handler);
2251
2252 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002253 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002254 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002255 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002256 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002257 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002258 }
2259 }
2260
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002262 if (err < 0)
2263 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002264
Wang Nanba504232016-02-26 09:31:54 +00002265 err = bpf__apply_obj_config();
2266 if (err) {
2267 char errbuf[BUFSIZ];
2268
2269 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2270 pr_err("ERROR: Apply config to BPF failed: %s\n",
2271 errbuf);
2272 goto out_error_open;
2273 }
2274
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002275 /*
2276 * Better not use !target__has_task() here because we need to cover the
2277 * case where no threads were specified in the command line, but a
2278 * workload was, and in that case we will fill in the thread_map when
2279 * we fork the workload in perf_evlist__prepare_workload.
2280 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002281 if (trace->filter_pids.nr > 0)
2282 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002283 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002284 err = perf_evlist__set_filter_pid(evlist, getpid());
2285
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002286 if (err < 0)
2287 goto out_error_mem;
2288
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002289 if (trace->ev_qualifier_ids.nr > 0) {
2290 err = trace__set_ev_qualifier_filter(trace);
2291 if (err < 0)
2292 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002293
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002294 pr_debug("event qualifier tracepoint filter: %s\n",
2295 trace->syscalls.events.sys_exit->filter);
2296 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002297
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002298 err = perf_evlist__apply_filters(evlist, &evsel);
2299 if (err < 0)
2300 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002301
Jiri Olsaf8850372013-11-28 17:57:22 +01002302 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002303 if (err < 0)
2304 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002305
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002306 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002307 perf_evlist__enable(evlist);
2308
Namhyung Kimf15eb532012-10-05 14:02:16 +09002309 if (forks)
2310 perf_evlist__start_workload(evlist);
2311
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002312 if (trace->opts.initial_delay) {
2313 usleep(trace->opts.initial_delay * 1000);
2314 perf_evlist__enable(evlist);
2315 }
2316
Jiri Olsae13798c2015-06-23 00:36:02 +02002317 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002318 evlist->threads->nr > 1 ||
2319 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002320again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002321 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322
2323 for (i = 0; i < evlist->nr_mmaps; i++) {
2324 union perf_event *event;
2325
2326 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002327 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002328
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002329 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002330
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002331 err = perf_evlist__parse_sample(evlist, event, &sample);
2332 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002333 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002334 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002335 }
2336
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002337 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002338next_event:
2339 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002340
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002341 if (interrupted)
2342 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002343
2344 if (done && !draining) {
2345 perf_evlist__disable(evlist);
2346 draining = true;
2347 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002348 }
2349 }
2350
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002351 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002352 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002353
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002354 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2355 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2356 draining = true;
2357
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002358 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002359 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002360 } else {
2361 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002362 }
2363
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002364out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002365 thread__zput(trace->current);
2366
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002367 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002368
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002369 if (!err) {
2370 if (trace->summary)
2371 trace__fprintf_thread_summary(trace, trace->output);
2372
2373 if (trace->show_tool_stats) {
2374 fprintf(trace->output, "Stats:\n "
2375 " vfs_getname : %" PRIu64 "\n"
2376 " proc_getname: %" PRIu64 "\n",
2377 trace->stats.vfs_getname,
2378 trace->stats.proc_getname);
2379 }
2380 }
David Ahernbf2575c2013-10-08 21:26:53 -06002381
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002382out_delete_evlist:
2383 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002384 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002385 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002386 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002387{
2388 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002389
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002390out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002391 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002392 goto out_error;
2393
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002394out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002395 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002396 goto out_error;
2397
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002398out_error_mmap:
2399 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2400 goto out_error;
2401
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002402out_error_open:
2403 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2404
2405out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002406 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302407 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002408
2409out_error_apply_filters:
2410 fprintf(trace->output,
2411 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2412 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002413 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002414 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002415}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002416out_error_mem:
2417 fprintf(trace->output, "Not enough memory to run!\n");
2418 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002419
2420out_errno:
2421 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2422 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002423}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002424
David Ahern6810fc92013-08-28 22:29:52 -06002425static int trace__replay(struct trace *trace)
2426{
2427 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002428 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002429 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002430 struct perf_data_file file = {
2431 .path = input_name,
2432 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002433 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002434 };
David Ahern6810fc92013-08-28 22:29:52 -06002435 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002436 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002437 int err = -1;
2438
2439 trace->tool.sample = trace__process_sample;
2440 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002441 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002442 trace->tool.comm = perf_event__process_comm;
2443 trace->tool.exit = perf_event__process_exit;
2444 trace->tool.fork = perf_event__process_fork;
2445 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302446 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002447 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302448 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002449
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002450 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002451 trace->tool.ordering_requires_timestamps = true;
2452
2453 /* add tid to output */
2454 trace->multiple_threads = true;
2455
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002456 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002457 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002458 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002459
David Ahernaa07df62016-11-25 09:29:52 -07002460 if (trace->opts.target.pid)
2461 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2462
2463 if (trace->opts.target.tid)
2464 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2465
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002466 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002467 goto out;
2468
David Ahern8fb598e2013-09-28 13:13:00 -06002469 trace->host = &session->machines.host;
2470
David Ahern6810fc92013-08-28 22:29:52 -06002471 err = perf_session__set_tracepoints_handlers(session, handlers);
2472 if (err)
2473 goto out;
2474
Namhyung Kim003824e2013-11-12 15:25:00 +09002475 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2476 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002477 /* older kernels have syscalls tp versus raw_syscalls */
2478 if (evsel == NULL)
2479 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2480 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002481
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002482 if (evsel &&
2483 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2484 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002485 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2486 goto out;
2487 }
2488
2489 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2490 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002491 if (evsel == NULL)
2492 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2493 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002494 if (evsel &&
2495 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2496 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002497 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002498 goto out;
2499 }
2500
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002501 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002502 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2503 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2504 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2505 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2506 evsel->handler = trace__pgfault;
2507 }
2508
David Ahern6810fc92013-08-28 22:29:52 -06002509 setup_pager();
2510
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002511 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002512 if (err)
2513 pr_err("Failed to process events, error %d", err);
2514
David Ahernbf2575c2013-10-08 21:26:53 -06002515 else if (trace->summary)
2516 trace__fprintf_thread_summary(trace, trace->output);
2517
David Ahern6810fc92013-08-28 22:29:52 -06002518out:
2519 perf_session__delete(session);
2520
2521 return err;
2522}
2523
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002524static size_t trace__fprintf_threads_header(FILE *fp)
2525{
2526 size_t printed;
2527
Pekka Enberg99ff7152013-11-12 16:42:14 +02002528 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002529
2530 return printed;
2531}
2532
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002533DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2534 struct stats *stats;
2535 double msecs;
2536 int syscall;
2537)
2538{
2539 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2540 struct stats *stats = source->priv;
2541
2542 entry->syscall = source->i;
2543 entry->stats = stats;
2544 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2545}
2546
David Ahernbf2575c2013-10-08 21:26:53 -06002547static size_t thread__dump_stats(struct thread_trace *ttrace,
2548 struct trace *trace, FILE *fp)
2549{
David Ahernbf2575c2013-10-08 21:26:53 -06002550 size_t printed = 0;
2551 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002552 struct rb_node *nd;
2553 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002554
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002555 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002556 return 0;
2557
2558 printed += fprintf(fp, "\n");
2559
Milian Wolff834fd462015-08-06 11:24:29 +02002560 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2561 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2562 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002563
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002564 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002565 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002566 if (stats) {
2567 double min = (double)(stats->min) / NSEC_PER_MSEC;
2568 double max = (double)(stats->max) / NSEC_PER_MSEC;
2569 double avg = avg_stats(stats);
2570 double pct;
2571 u64 n = (u64) stats->n;
2572
2573 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2574 avg /= NSEC_PER_MSEC;
2575
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002576 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002577 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002578 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002579 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002580 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002581 }
David Ahernbf2575c2013-10-08 21:26:53 -06002582 }
2583
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002584 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002585 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002586
2587 return printed;
2588}
2589
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002590static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002591{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002592 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002593 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002594 double ratio;
2595
2596 if (ttrace == NULL)
2597 return 0;
2598
2599 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2600
Pekka Enberg15e65c62013-11-14 18:43:30 +02002601 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002602 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002603 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002604 if (ttrace->pfmaj)
2605 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2606 if (ttrace->pfmin)
2607 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002608 if (trace->sched)
2609 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2610 else if (fputc('\n', fp) != EOF)
2611 ++printed;
2612
David Ahernbf2575c2013-10-08 21:26:53 -06002613 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002614
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002615 return printed;
2616}
David Ahern896cbb52013-09-28 13:12:59 -06002617
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002618static unsigned long thread__nr_events(struct thread_trace *ttrace)
2619{
2620 return ttrace ? ttrace->nr_events : 0;
2621}
2622
2623DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2624 struct thread *thread;
2625)
2626{
2627 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002628}
2629
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002630static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2631{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002632 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2633 size_t printed = trace__fprintf_threads_header(fp);
2634 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002635
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002636 if (threads == NULL) {
2637 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2638 return 0;
2639 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002640
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002641 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002642 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2643
2644 resort_rb__delete(threads);
2645
2646 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002647}
2648
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002649static int trace__set_duration(const struct option *opt, const char *str,
2650 int unset __maybe_unused)
2651{
2652 struct trace *trace = opt->value;
2653
2654 trace->duration_filter = atof(str);
2655 return 0;
2656}
2657
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002658static int trace__set_filter_pids(const struct option *opt, const char *str,
2659 int unset __maybe_unused)
2660{
2661 int ret = -1;
2662 size_t i;
2663 struct trace *trace = opt->value;
2664 /*
2665 * FIXME: introduce a intarray class, plain parse csv and create a
2666 * { int nr, int entries[] } struct...
2667 */
2668 struct intlist *list = intlist__new(str);
2669
2670 if (list == NULL)
2671 return -1;
2672
2673 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2674 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2675
2676 if (trace->filter_pids.entries == NULL)
2677 goto out;
2678
2679 trace->filter_pids.entries[0] = getpid();
2680
2681 for (i = 1; i < trace->filter_pids.nr; ++i)
2682 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2683
2684 intlist__delete(list);
2685 ret = 0;
2686out:
2687 return ret;
2688}
2689
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002690static int trace__open_output(struct trace *trace, const char *filename)
2691{
2692 struct stat st;
2693
2694 if (!stat(filename, &st) && st.st_size) {
2695 char oldname[PATH_MAX];
2696
2697 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2698 unlink(oldname);
2699 rename(filename, oldname);
2700 }
2701
2702 trace->output = fopen(filename, "w");
2703
2704 return trace->output == NULL ? -errno : 0;
2705}
2706
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002707static int parse_pagefaults(const struct option *opt, const char *str,
2708 int unset __maybe_unused)
2709{
2710 int *trace_pgfaults = opt->value;
2711
2712 if (strcmp(str, "all") == 0)
2713 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2714 else if (strcmp(str, "maj") == 0)
2715 *trace_pgfaults |= TRACE_PFMAJ;
2716 else if (strcmp(str, "min") == 0)
2717 *trace_pgfaults |= TRACE_PFMIN;
2718 else
2719 return -1;
2720
2721 return 0;
2722}
2723
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002724static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2725{
2726 struct perf_evsel *evsel;
2727
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002728 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002729 evsel->handler = handler;
2730}
2731
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002732/*
2733 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2734 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2735 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2736 *
2737 * It'd be better to introduce a parse_options() variant that would return a
2738 * list with the terms it didn't match to an event...
2739 */
2740static int trace__parse_events_option(const struct option *opt, const char *str,
2741 int unset __maybe_unused)
2742{
2743 struct trace *trace = (struct trace *)opt->value;
2744 const char *s = str;
2745 char *sep = NULL, *lists[2] = { NULL, NULL, };
2746 int len = strlen(str), err = -1, list;
2747 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2748 char group_name[PATH_MAX];
2749
2750 if (strace_groups_dir == NULL)
2751 return -1;
2752
2753 if (*s == '!') {
2754 ++s;
2755 trace->not_ev_qualifier = true;
2756 }
2757
2758 while (1) {
2759 if ((sep = strchr(s, ',')) != NULL)
2760 *sep = '\0';
2761
2762 list = 0;
2763 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2764 list = 1;
2765 } else {
2766 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2767 if (access(group_name, R_OK) == 0)
2768 list = 1;
2769 }
2770
2771 if (lists[list]) {
2772 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2773 } else {
2774 lists[list] = malloc(len);
2775 if (lists[list] == NULL)
2776 goto out;
2777 strcpy(lists[list], s);
2778 }
2779
2780 if (!sep)
2781 break;
2782
2783 *sep = ',';
2784 s = sep + 1;
2785 }
2786
2787 if (lists[1] != NULL) {
2788 struct strlist_config slist_config = {
2789 .dirname = strace_groups_dir,
2790 };
2791
2792 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2793 if (trace->ev_qualifier == NULL) {
2794 fputs("Not enough memory to parse event qualifier", trace->output);
2795 goto out;
2796 }
2797
2798 if (trace__validate_ev_qualifier(trace))
2799 goto out;
2800 }
2801
2802 err = 0;
2803
2804 if (lists[0]) {
2805 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2806 "event selector. use 'perf list' to list available events",
2807 parse_events_option);
2808 err = parse_events_option(&o, lists[0], 0);
2809 }
2810out:
2811 if (sep)
2812 *sep = ',';
2813
2814 return err;
2815}
2816
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002817int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002818{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002819 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002820 "perf trace [<options>] [<command>]",
2821 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002822 "perf trace record [<options>] [<command>]",
2823 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002824 NULL
2825 };
2826 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002827 .syscalls = {
2828 . max = -1,
2829 },
2830 .opts = {
2831 .target = {
2832 .uid = UINT_MAX,
2833 .uses_mmap = true,
2834 },
2835 .user_freq = UINT_MAX,
2836 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002837 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002838 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002839 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002840 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002841 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002842 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002843 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002844 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002845 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002846 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002847 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002848 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002849 OPT_CALLBACK('e', "event", &trace, "event",
2850 "event/syscall selector. use 'perf list' to list available events",
2851 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002852 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2853 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002854 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002855 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2856 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002857 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002858 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002859 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2860 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002861 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002862 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002863 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2864 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002865 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002866 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002867 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002868 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002869 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002870 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002871 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2872 "number of mmap data pages",
2873 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002874 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002875 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002876 OPT_CALLBACK(0, "duration", &trace, "float",
2877 "show only events with duration > N.M ms",
2878 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002879 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002880 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002881 OPT_BOOLEAN('T', "time", &trace.full_time,
2882 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002883 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2884 "Show only syscall summary with statistics"),
2885 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2886 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002887 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2888 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002889 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002890 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002891 OPT_CALLBACK(0, "call-graph", &trace.opts,
2892 "record_mode[,record_size]", record_callchain_help,
2893 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002894 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2895 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002896 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2897 "Set the minimum stack depth when parsing the callchain, "
2898 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002899 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2900 "Set the maximum stack depth when parsing the callchain, "
2901 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002902 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002903 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2904 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002905 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2906 "ms to wait before starting measurement after program "
2907 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002908 OPT_END()
2909 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002910 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002911 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002912 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002913 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002914 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002915
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002916 signal(SIGSEGV, sighandler_dump_stack);
2917 signal(SIGFPE, sighandler_dump_stack);
2918
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002919 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002920 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002921
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002922 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002923 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002924 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002925 goto out;
2926 }
2927
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002928 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2929 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002930
Wang Nand7888572016-04-08 15:07:24 +00002931 err = bpf__setup_stdout(trace.evlist);
2932 if (err) {
2933 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2934 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2935 goto out;
2936 }
2937
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002938 err = -1;
2939
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002940 if (trace.trace_pgfaults) {
2941 trace.opts.sample_address = true;
2942 trace.opts.sample_time = true;
2943 }
2944
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002945 if (trace.opts.mmap_pages == UINT_MAX)
2946 mmap_pages_user_set = false;
2947
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002948 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002949 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002950 max_stack_user_set = false;
2951 }
2952
2953#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002954 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002955 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2956#endif
2957
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002958 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002959 if (!mmap_pages_user_set && geteuid() == 0)
2960 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2961
Milian Wolff566a0882016-04-08 13:34:15 +02002962 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002963 }
Milian Wolff566a0882016-04-08 13:34:15 +02002964
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002965 if (trace.evlist->nr_entries > 0)
2966 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2967
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002968 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2969 return trace__record(&trace, argc-1, &argv[1]);
2970
2971 /* summary_only implies summary option, but don't overwrite summary if set */
2972 if (trace.summary_only)
2973 trace.summary = trace.summary_only;
2974
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002975 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2976 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002977 pr_err("Please specify something to trace.\n");
2978 return -1;
2979 }
2980
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002981 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002982 pr_err("The -e option can't be used with --no-syscalls.\n");
2983 goto out;
2984 }
2985
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002986 if (output_name != NULL) {
2987 err = trace__open_output(&trace, output_name);
2988 if (err < 0) {
2989 perror("failed to create output file");
2990 goto out;
2991 }
2992 }
2993
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002994 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2995
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002996 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002997 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002998 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002999 fprintf(trace.output, "%s", bf);
3000 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003001 }
3002
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003003 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003004 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003005 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003006 fprintf(trace.output, "%s", bf);
3007 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003008 }
3009
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003010 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003011 trace.opts.target.system_wide = true;
3012
David Ahern6810fc92013-08-28 22:29:52 -06003013 if (input_name)
3014 err = trace__replay(&trace);
3015 else
3016 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003017
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003018out_close:
3019 if (output_name != NULL)
3020 fclose(trace.output);
3021out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003022 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003023}