blob: 7379792a65045f5f478a9ec382bd703e5623394e [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -060027#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060029#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030030#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060031#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030032#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060033#include "util/stat.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010034#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070035#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000036#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020037#include "callchain.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030038#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030039#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030040
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030041#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030042#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030043#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020044#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030045#include <linux/filter.h>
46#include <linux/audit.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030047#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030048#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030049#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030050
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030051#ifndef O_CLOEXEC
52# define O_CLOEXEC 02000000
53#endif
54
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030055struct trace {
56 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030057 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030058 struct {
59 int max;
60 struct syscall *table;
61 struct {
62 struct perf_evsel *sys_enter,
63 *sys_exit;
64 } events;
65 } syscalls;
66 struct record_opts opts;
67 struct perf_evlist *evlist;
68 struct machine *host;
69 struct thread *current;
70 u64 base_time;
71 FILE *output;
72 unsigned long nr_events;
73 struct strlist *ev_qualifier;
74 struct {
75 size_t nr;
76 int *entries;
77 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030078 struct {
79 size_t nr;
80 pid_t *entries;
81 } filter_pids;
82 double duration_filter;
83 double runtime_ms;
84 struct {
85 u64 vfs_getname,
86 proc_getname;
87 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030088 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030089 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030090 bool not_ev_qualifier;
91 bool live;
92 bool full_time;
93 bool sched;
94 bool multiple_threads;
95 bool summary;
96 bool summary_only;
97 bool show_comm;
98 bool show_tool_stats;
99 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300100 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300101 bool force;
102 bool vfs_getname;
103 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300104 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300105};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300106
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300107struct tp_field {
108 int offset;
109 union {
110 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
111 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
112 };
113};
114
115#define TP_UINT_FIELD(bits) \
116static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
117{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500118 u##bits value; \
119 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
120 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300121}
122
123TP_UINT_FIELD(8);
124TP_UINT_FIELD(16);
125TP_UINT_FIELD(32);
126TP_UINT_FIELD(64);
127
128#define TP_UINT_FIELD__SWAPPED(bits) \
129static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
130{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500131 u##bits value; \
132 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300133 return bswap_##bits(value);\
134}
135
136TP_UINT_FIELD__SWAPPED(16);
137TP_UINT_FIELD__SWAPPED(32);
138TP_UINT_FIELD__SWAPPED(64);
139
140static int tp_field__init_uint(struct tp_field *field,
141 struct format_field *format_field,
142 bool needs_swap)
143{
144 field->offset = format_field->offset;
145
146 switch (format_field->size) {
147 case 1:
148 field->integer = tp_field__u8;
149 break;
150 case 2:
151 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
152 break;
153 case 4:
154 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
155 break;
156 case 8:
157 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
158 break;
159 default:
160 return -1;
161 }
162
163 return 0;
164}
165
166static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
167{
168 return sample->raw_data + field->offset;
169}
170
171static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
172{
173 field->offset = format_field->offset;
174 field->pointer = tp_field__ptr;
175 return 0;
176}
177
178struct syscall_tp {
179 struct tp_field id;
180 union {
181 struct tp_field args, ret;
182 };
183};
184
185static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
186 struct tp_field *field,
187 const char *name)
188{
189 struct format_field *format_field = perf_evsel__field(evsel, name);
190
191 if (format_field == NULL)
192 return -1;
193
194 return tp_field__init_uint(field, format_field, evsel->needs_swap);
195}
196
197#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
198 ({ struct syscall_tp *sc = evsel->priv;\
199 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
200
201static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
202 struct tp_field *field,
203 const char *name)
204{
205 struct format_field *format_field = perf_evsel__field(evsel, name);
206
207 if (format_field == NULL)
208 return -1;
209
210 return tp_field__init_ptr(field, format_field);
211}
212
213#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
214 ({ struct syscall_tp *sc = evsel->priv;\
215 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
216
217static void perf_evsel__delete_priv(struct perf_evsel *evsel)
218{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300219 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300220 perf_evsel__delete(evsel);
221}
222
Namhyung Kim96695d42013-11-12 08:51:45 -0300223static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
224{
225 evsel->priv = malloc(sizeof(struct syscall_tp));
226 if (evsel->priv != NULL) {
227 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
228 goto out_delete;
229
230 evsel->handler = handler;
231 return 0;
232 }
233
234 return -ENOMEM;
235
236out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300237 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300238 return -ENOENT;
239}
240
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300241static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300242{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300243 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300244
David Ahern9aca7f12013-12-04 19:41:39 -0700245 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200246 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700247 evsel = perf_evsel__newtp("syscalls", direction);
248
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200249 if (IS_ERR(evsel))
250 return NULL;
251
252 if (perf_evsel__init_syscall_tp(evsel, handler))
253 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300254
255 return evsel;
256
257out_delete:
258 perf_evsel__delete_priv(evsel);
259 return NULL;
260}
261
262#define perf_evsel__sc_tp_uint(evsel, name, sample) \
263 ({ struct syscall_tp *fields = evsel->priv; \
264 fields->name.integer(&fields->name, sample); })
265
266#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
267 ({ struct syscall_tp *fields = evsel->priv; \
268 fields->name.pointer(&fields->name, sample); })
269
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300270struct syscall_arg {
271 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300272 struct thread *thread;
273 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300274 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300275 u8 idx;
276 u8 mask;
277};
278
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300279struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300280 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300281 int nr_entries;
282 const char **entries;
283};
284
285#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
286 .nr_entries = ARRAY_SIZE(array), \
287 .entries = array, \
288}
289
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300290#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
291 .offset = off, \
292 .nr_entries = ARRAY_SIZE(array), \
293 .entries = array, \
294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300301 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302
303 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300304 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305
306 return scnprintf(bf, size, "%s", sa->entries[idx]);
307}
308
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300309static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
310 struct syscall_arg *arg)
311{
312 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
313}
314
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300315#define SCA_STRARRAY syscall_arg__scnprintf_strarray
316
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300317#if defined(__i386__) || defined(__x86_64__)
318/*
319 * FIXME: Make this available to all arches as soon as the ioctl beautifier
320 * gets rewritten to support all arches.
321 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300322static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
323 struct syscall_arg *arg)
324{
325 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
326}
327
328#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300329#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300330
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300331static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
332 struct syscall_arg *arg);
333
334#define SCA_FD syscall_arg__scnprintf_fd
335
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300336#ifndef AT_FDCWD
337#define AT_FDCWD -100
338#endif
339
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300340static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
341 struct syscall_arg *arg)
342{
343 int fd = arg->val;
344
345 if (fd == AT_FDCWD)
346 return scnprintf(bf, size, "CWD");
347
348 return syscall_arg__scnprintf_fd(bf, size, arg);
349}
350
351#define SCA_FDAT syscall_arg__scnprintf_fd_at
352
353static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
354 struct syscall_arg *arg);
355
356#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
357
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300358static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300359 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300360{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300361 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300362}
363
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300364#define SCA_HEX syscall_arg__scnprintf_hex
365
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300366static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
367 struct syscall_arg *arg)
368{
369 return scnprintf(bf, size, "%d", arg->val);
370}
371
372#define SCA_INT syscall_arg__scnprintf_int
373
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300374static const char *bpf_cmd[] = {
375 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
376 "MAP_GET_NEXT_KEY", "PROG_LOAD",
377};
378static DEFINE_STRARRAY(bpf_cmd);
379
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300380static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
381static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300382
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300383static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
384static DEFINE_STRARRAY(itimers);
385
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300386static const char *keyctl_options[] = {
387 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
388 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
389 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
390 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
391 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
392};
393static DEFINE_STRARRAY(keyctl_options);
394
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300395static const char *whences[] = { "SET", "CUR", "END",
396#ifdef SEEK_DATA
397"DATA",
398#endif
399#ifdef SEEK_HOLE
400"HOLE",
401#endif
402};
403static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300404
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300405static const char *fcntl_cmds[] = {
406 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
407 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
408 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
409 "F_GETOWNER_UIDS",
410};
411static DEFINE_STRARRAY(fcntl_cmds);
412
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300413static const char *rlimit_resources[] = {
414 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
415 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
416 "RTTIME",
417};
418static DEFINE_STRARRAY(rlimit_resources);
419
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300420static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
421static DEFINE_STRARRAY(sighow);
422
David Ahern4f8c1b72013-09-22 19:45:00 -0600423static const char *clockid[] = {
424 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300425 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
426 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600427};
428static DEFINE_STRARRAY(clockid);
429
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300430static const char *socket_families[] = {
431 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
432 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
433 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
434 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
435 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
436 "ALG", "NFC", "VSOCK",
437};
438static DEFINE_STRARRAY(socket_families);
439
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300440static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
441 struct syscall_arg *arg)
442{
443 size_t printed = 0;
444 int mode = arg->val;
445
446 if (mode == F_OK) /* 0 */
447 return scnprintf(bf, size, "F");
448#define P_MODE(n) \
449 if (mode & n##_OK) { \
450 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
451 mode &= ~n##_OK; \
452 }
453
454 P_MODE(R);
455 P_MODE(W);
456 P_MODE(X);
457#undef P_MODE
458
459 if (mode)
460 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
461
462 return printed;
463}
464
465#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
466
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300467static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
468 struct syscall_arg *arg);
469
470#define SCA_FILENAME syscall_arg__scnprintf_filename
471
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300472static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
473 struct syscall_arg *arg)
474{
475 int printed = 0, flags = arg->val;
476
477#define P_FLAG(n) \
478 if (flags & O_##n) { \
479 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
480 flags &= ~O_##n; \
481 }
482
483 P_FLAG(CLOEXEC);
484 P_FLAG(NONBLOCK);
485#undef P_FLAG
486
487 if (flags)
488 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
489
490 return printed;
491}
492
493#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
494
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300495#if defined(__i386__) || defined(__x86_64__)
496/*
497 * FIXME: Make this available to all arches.
498 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300499#define TCGETS 0x5401
500
501static const char *tioctls[] = {
502 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
503 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
504 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
505 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
506 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
507 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
508 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
509 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
510 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
511 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
512 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
513 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
514 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
515 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
516 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
517};
518
519static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300520#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300521
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300522#ifndef GRND_NONBLOCK
523#define GRND_NONBLOCK 0x0001
524#endif
525#ifndef GRND_RANDOM
526#define GRND_RANDOM 0x0002
527#endif
528
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300529static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
530 struct syscall_arg *arg)
531{
532 int printed = 0, flags = arg->val;
533
534#define P_FLAG(n) \
535 if (flags & GRND_##n) { \
536 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
537 flags &= ~GRND_##n; \
538 }
539
540 P_FLAG(RANDOM);
541 P_FLAG(NONBLOCK);
542#undef P_FLAG
543
544 if (flags)
545 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
546
547 return printed;
548}
549
550#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
551
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300552#define STRARRAY(arg, name, array) \
553 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
554 .arg_parm = { [arg] = &strarray__##array, }
555
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300556#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300557#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300558#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300559#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300560#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300561#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300562#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300563#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300564#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300565#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300566#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300567#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300568#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300569#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300570
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300571static struct syscall_fmt {
572 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300573 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300574 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300575 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300576 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300577 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300578 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300579 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300580} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300581 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300582 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300583 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300584 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300585 { .name = "brk", .hexret = true,
586 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300587 { .name = "chdir", .errmsg = true, },
588 { .name = "chmod", .errmsg = true, },
589 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600590 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300591 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300592 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300593 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300594 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300595 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300596 { .name = "dup", .errmsg = true, },
597 { .name = "dup2", .errmsg = true, },
598 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300599 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300600 { .name = "eventfd2", .errmsg = true,
601 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300602 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300603 { .name = "fadvise64", .errmsg = true, },
604 { .name = "fallocate", .errmsg = true, },
605 { .name = "fchdir", .errmsg = true, },
606 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300607 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300608 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300609 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300610 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300611 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300612 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300613 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300614 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300615 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300616 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300617 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
618 { .name = "fsetxattr", .errmsg = true, },
619 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300620 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300621 { .name = "fstatfs", .errmsg = true, },
622 { .name = "fsync", .errmsg = true, },
623 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300624 { .name = "futex", .errmsg = true,
625 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300626 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300627 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300628 { .name = "getdents", .errmsg = true, },
629 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300630 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300631 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300632 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300633 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300634 { .name = "getrandom", .errmsg = true,
635 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300636 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300637 { .name = "getxattr", .errmsg = true, },
638 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300639 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300640 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300641#if defined(__i386__) || defined(__x86_64__)
642/*
643 * FIXME: Make this available to all arches.
644 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300645 [1] = SCA_STRHEXARRAY, /* cmd */
646 [2] = SCA_HEX, /* arg */ },
647 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300648#else
649 [2] = SCA_HEX, /* arg */ }, },
650#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300651 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300652 { .name = "kill", .errmsg = true,
653 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300654 { .name = "lchown", .errmsg = true, },
655 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300656 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300657 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300658 { .name = "listxattr", .errmsg = true, },
659 { .name = "llistxattr", .errmsg = true, },
660 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300661 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300662 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300663 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300664 { .name = "lsetxattr", .errmsg = true, },
665 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
666 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300667 { .name = "madvise", .errmsg = true,
668 .arg_scnprintf = { [0] = SCA_HEX, /* start */
669 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300670 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300671 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300672 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
673 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300674 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300675 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300676 { .name = "mlock", .errmsg = true,
677 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
678 { .name = "mlockall", .errmsg = true,
679 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300680 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300681 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300682 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300683 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300684 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300685 .arg_scnprintf = { [0] = SCA_HEX, /* start */
686 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300687 { .name = "mq_unlink", .errmsg = true,
688 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300689 { .name = "mremap", .hexret = true,
690 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300691 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300692 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300693 { .name = "munlock", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300695 { .name = "munmap", .errmsg = true,
696 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300697 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300698 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300699 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300700 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300701 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300702 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300703 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300704 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
705 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300706 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300707 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
708 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300709 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300710 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300711 [3] = SCA_FD, /* group_fd */
712 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300713 { .name = "pipe2", .errmsg = true,
714 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300715 { .name = "poll", .errmsg = true, .timeout = true, },
716 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300717 { .name = "pread", .errmsg = true, .alias = "pread64", },
718 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300719 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300720 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
721 { .name = "pwritev", .errmsg = true, },
722 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300723 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300724 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300725 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300726 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300727 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300728 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300729 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300730 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300731 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300732 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300733 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300734 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300735 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300736 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300737 { .name = "rt_sigaction", .errmsg = true,
738 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300739 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300740 { .name = "rt_sigqueueinfo", .errmsg = true,
741 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
742 { .name = "rt_tgsigqueueinfo", .errmsg = true,
743 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300744 { .name = "sched_getattr", .errmsg = true, },
745 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300746 { .name = "sched_setscheduler", .errmsg = true,
747 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300748 { .name = "seccomp", .errmsg = true,
749 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
750 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300751 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300752 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300753 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300754 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300755 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300756 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300757 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300758 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300759 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300760 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300761 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300762 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300763 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300764 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300765 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
766 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300767 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300768 { .name = "socketpair", .errmsg = true,
769 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
770 [1] = SCA_SK_TYPE, /* type */ },
771 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300772 { .name = "stat", .errmsg = true, .alias = "newstat", },
773 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300774 { .name = "swapoff", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
776 { .name = "swapon", .errmsg = true,
777 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300778 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300779 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300780 { .name = "tgkill", .errmsg = true,
781 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
782 { .name = "tkill", .errmsg = true,
783 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300784 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300785 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300786 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300787 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
788 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300789 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300790 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
791 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300792 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300793 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300794 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300795 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300796 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300797 { .name = "write", .errmsg = true, },
798 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300799};
800
801static int syscall_fmt__cmp(const void *name, const void *fmtp)
802{
803 const struct syscall_fmt *fmt = fmtp;
804 return strcmp(name, fmt->name);
805}
806
807static struct syscall_fmt *syscall_fmt__find(const char *name)
808{
809 const int nmemb = ARRAY_SIZE(syscall_fmts);
810 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
811}
812
813struct syscall {
814 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300815 int nr_args;
816 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300818 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300819 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300820 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300821 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300822};
823
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300824/*
825 * We need to have this 'calculated' boolean because in some cases we really
826 * don't know what is the duration of a syscall, for instance, when we start
827 * a session and some threads are waiting for a syscall to finish, say 'poll',
828 * in which case all we can do is to print "( ? ) for duration and for the
829 * start timestamp.
830 */
831static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200832{
833 double duration = (double)t / NSEC_PER_MSEC;
834 size_t printed = fprintf(fp, "(");
835
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300836 if (!calculated)
837 printed += fprintf(fp, " ? ");
838 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200839 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
840 else if (duration >= 0.01)
841 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
842 else
843 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300844 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200845}
846
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300847/**
848 * filename.ptr: The filename char pointer that will be vfs_getname'd
849 * filename.entry_str_pos: Where to insert the string translated from
850 * filename.ptr by the vfs_getname tracepoint/kprobe.
851 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300852struct thread_trace {
853 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300854 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300855 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400856 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300857 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300858 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300859 struct {
860 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300861 short int entry_str_pos;
862 bool pending_open;
863 unsigned int namelen;
864 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300865 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300866 struct {
867 int max;
868 char **table;
869 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600870
871 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300872};
873
874static struct thread_trace *thread_trace__new(void)
875{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300876 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
877
878 if (ttrace)
879 ttrace->paths.max = -1;
880
David Ahernbf2575c2013-10-08 21:26:53 -0600881 ttrace->syscall_stats = intlist__new(NULL);
882
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300883 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300884}
885
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300886static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300887{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300888 struct thread_trace *ttrace;
889
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890 if (thread == NULL)
891 goto fail;
892
Namhyung Kim89dceb22014-10-06 09:46:03 +0900893 if (thread__priv(thread) == NULL)
894 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300895
Namhyung Kim89dceb22014-10-06 09:46:03 +0900896 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897 goto fail;
898
Namhyung Kim89dceb22014-10-06 09:46:03 +0900899 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300900 ++ttrace->nr_events;
901
902 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300903fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300904 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300905 "WARNING: not enough memory, dropping samples!\n");
906 return NULL;
907}
908
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400909#define TRACE_PFMAJ (1 << 0)
910#define TRACE_PFMIN (1 << 1)
911
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300912static const size_t trace__entry_str_size = 2048;
913
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300914static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300915{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900916 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300917
918 if (fd > ttrace->paths.max) {
919 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
920
921 if (npath == NULL)
922 return -1;
923
924 if (ttrace->paths.max != -1) {
925 memset(npath + ttrace->paths.max + 1, 0,
926 (fd - ttrace->paths.max) * sizeof(char *));
927 } else {
928 memset(npath, 0, (fd + 1) * sizeof(char *));
929 }
930
931 ttrace->paths.table = npath;
932 ttrace->paths.max = fd;
933 }
934
935 ttrace->paths.table[fd] = strdup(pathname);
936
937 return ttrace->paths.table[fd] != NULL ? 0 : -1;
938}
939
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300940static int thread__read_fd_path(struct thread *thread, int fd)
941{
942 char linkname[PATH_MAX], pathname[PATH_MAX];
943 struct stat st;
944 int ret;
945
946 if (thread->pid_ == thread->tid) {
947 scnprintf(linkname, sizeof(linkname),
948 "/proc/%d/fd/%d", thread->pid_, fd);
949 } else {
950 scnprintf(linkname, sizeof(linkname),
951 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
952 }
953
954 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
955 return -1;
956
957 ret = readlink(linkname, pathname, sizeof(pathname));
958
959 if (ret < 0 || ret > st.st_size)
960 return -1;
961
962 pathname[ret] = '\0';
963 return trace__set_fd_pathname(thread, fd, pathname);
964}
965
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300966static const char *thread__fd_path(struct thread *thread, int fd,
967 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300968{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900969 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300970
971 if (ttrace == NULL)
972 return NULL;
973
974 if (fd < 0)
975 return NULL;
976
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300977 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300978 if (!trace->live)
979 return NULL;
980 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300981 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300982 return NULL;
983 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984
985 return ttrace->paths.table[fd];
986}
987
988static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
989 struct syscall_arg *arg)
990{
991 int fd = arg->val;
992 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300993 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994
995 if (path)
996 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
997
998 return printed;
999}
1000
1001static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1002 struct syscall_arg *arg)
1003{
1004 int fd = arg->val;
1005 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001006 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001007
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001008 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1009 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001010
1011 return printed;
1012}
1013
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001014static void thread__set_filename_pos(struct thread *thread, const char *bf,
1015 unsigned long ptr)
1016{
1017 struct thread_trace *ttrace = thread__priv(thread);
1018
1019 ttrace->filename.ptr = ptr;
1020 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1021}
1022
1023static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1024 struct syscall_arg *arg)
1025{
1026 unsigned long ptr = arg->val;
1027
1028 if (!arg->trace->vfs_getname)
1029 return scnprintf(bf, size, "%#x", ptr);
1030
1031 thread__set_filename_pos(arg->thread, bf, ptr);
1032 return 0;
1033}
1034
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001035static bool trace__filter_duration(struct trace *trace, double t)
1036{
1037 return t < (trace->duration_filter * NSEC_PER_MSEC);
1038}
1039
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001040static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001041{
1042 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1043
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001044 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001045}
1046
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001047/*
1048 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1049 * using ttrace->entry_time for a thread that receives a sys_exit without
1050 * first having received a sys_enter ("poll" issued before tracing session
1051 * starts, lost sys_enter exit due to ring buffer overflow).
1052 */
1053static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1054{
1055 if (tstamp > 0)
1056 return __trace__fprintf_tstamp(trace, tstamp, fp);
1057
1058 return fprintf(fp, " ? ");
1059}
1060
Namhyung Kimf15eb532012-10-05 14:02:16 +09001061static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001062static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001063
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001064static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001065{
1066 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001067 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001068}
1069
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001070static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001071 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001072{
1073 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001074 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001075
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001076 if (trace->multiple_threads) {
1077 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001078 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001079 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001080 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001081
1082 return printed;
1083}
1084
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001085static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001086 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001087{
1088 int ret = 0;
1089
1090 switch (event->header.type) {
1091 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001092 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001093 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001094 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001095 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001097 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098 break;
1099 }
1100
1101 return ret;
1102}
1103
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001104static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001106 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107 struct machine *machine)
1108{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001109 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001110 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111}
1112
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001113static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1114{
1115 struct machine *machine = vmachine;
1116
1117 if (machine->kptr_restrict_warned)
1118 return NULL;
1119
1120 if (symbol_conf.kptr_restrict) {
1121 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1122 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1123 "Kernel samples will not be resolved.\n");
1124 machine->kptr_restrict_warned = true;
1125 return NULL;
1126 }
1127
1128 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1129}
1130
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1132{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001133 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001134
1135 if (err)
1136 return err;
1137
David Ahern8fb598e2013-09-28 13:13:00 -06001138 trace->host = machine__new_host();
1139 if (trace->host == NULL)
1140 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001141
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001142 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001143 return -errno;
1144
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001145 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001146 evlist->threads, trace__tool_process, false,
1147 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 if (err)
1149 symbol__exit();
1150
1151 return err;
1152}
1153
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001154static int syscall__set_arg_fmts(struct syscall *sc)
1155{
1156 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001157 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001158
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001159 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001160 if (sc->arg_scnprintf == NULL)
1161 return -1;
1162
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001163 if (sc->fmt)
1164 sc->arg_parm = sc->fmt->arg_parm;
1165
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001166 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001167 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1168 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001169 else if (strcmp(field->type, "const char *") == 0 &&
1170 (strcmp(field->name, "filename") == 0 ||
1171 strcmp(field->name, "path") == 0 ||
1172 strcmp(field->name, "pathname") == 0))
1173 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001174 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001175 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001176 else if (strcmp(field->type, "pid_t") == 0)
1177 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001178 else if (strcmp(field->type, "umode_t") == 0)
1179 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001180 else if ((strcmp(field->type, "int") == 0 ||
1181 strcmp(field->type, "unsigned int") == 0 ||
1182 strcmp(field->type, "long") == 0) &&
1183 (len = strlen(field->name)) >= 2 &&
1184 strcmp(field->name + len - 2, "fd") == 0) {
1185 /*
1186 * /sys/kernel/tracing/events/syscalls/sys_enter*
1187 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1188 * 65 int
1189 * 23 unsigned int
1190 * 7 unsigned long
1191 */
1192 sc->arg_scnprintf[idx] = SCA_FD;
1193 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001194 ++idx;
1195 }
1196
1197 return 0;
1198}
1199
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001200static int trace__read_syscall_info(struct trace *trace, int id)
1201{
1202 char tp_name[128];
1203 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001204 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001205
1206 if (name == NULL)
1207 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001208
1209 if (id > trace->syscalls.max) {
1210 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1211
1212 if (nsyscalls == NULL)
1213 return -1;
1214
1215 if (trace->syscalls.max != -1) {
1216 memset(nsyscalls + trace->syscalls.max + 1, 0,
1217 (id - trace->syscalls.max) * sizeof(*sc));
1218 } else {
1219 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1220 }
1221
1222 trace->syscalls.table = nsyscalls;
1223 trace->syscalls.max = id;
1224 }
1225
1226 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001227 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001228
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001229 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001230
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001231 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001232 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001233
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001234 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001235 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001236 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001237 }
1238
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001239 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001240 return -1;
1241
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001242 sc->args = sc->tp_format->format.fields;
1243 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001244 /*
1245 * We need to check and discard the first variable '__syscall_nr'
1246 * or 'nr' that mean the syscall number. It is needless here.
1247 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1248 */
1249 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001250 sc->args = sc->args->next;
1251 --sc->nr_args;
1252 }
1253
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001254 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1255
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001256 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001257}
1258
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001259static int trace__validate_ev_qualifier(struct trace *trace)
1260{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001261 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001262 struct str_node *pos;
1263
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001264 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1265 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1266 sizeof(trace->ev_qualifier_ids.entries[0]));
1267
1268 if (trace->ev_qualifier_ids.entries == NULL) {
1269 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1270 trace->output);
1271 err = -EINVAL;
1272 goto out;
1273 }
1274
1275 i = 0;
1276
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001277 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001278 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001279 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001280
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001281 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001282 if (err == 0) {
1283 fputs("Error:\tInvalid syscall ", trace->output);
1284 err = -EINVAL;
1285 } else {
1286 fputs(", ", trace->output);
1287 }
1288
1289 fputs(sc, trace->output);
1290 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001291
1292 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001293 }
1294
1295 if (err < 0) {
1296 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1297 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001298 zfree(&trace->ev_qualifier_ids.entries);
1299 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001300 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001301out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001302 return err;
1303}
1304
David Ahern55d43bca2015-02-19 15:00:22 -05001305/*
1306 * args is to be interpreted as a series of longs but we need to handle
1307 * 8-byte unaligned accesses. args points to raw_data within the event
1308 * and raw_data is guaranteed to be 8-byte unaligned because it is
1309 * preceded by raw_size which is a u32. So we need to copy args to a temp
1310 * variable to read it. Most notably this avoids extended load instructions
1311 * on unaligned addresses
1312 */
1313
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001314static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001315 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001316 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001317{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001318 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001319 unsigned char *p;
1320 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001322 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001323 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001324 u8 bit = 1;
1325 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001326 .idx = 0,
1327 .mask = 0,
1328 .trace = trace,
1329 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001330 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001331
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001332 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001333 field = field->next, ++arg.idx, bit <<= 1) {
1334 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001335 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001336
1337 /* special care for unaligned accesses */
1338 p = args + sizeof(unsigned long) * arg.idx;
1339 memcpy(&val, p, sizeof(val));
1340
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001341 /*
1342 * Suppress this argument if its value is zero and
1343 * and we don't have a string associated in an
1344 * strarray for it.
1345 */
David Ahern55d43bca2015-02-19 15:00:22 -05001346 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001347 !(sc->arg_scnprintf &&
1348 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1349 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001350 continue;
1351
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001352 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001353 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001354 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001355 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001356 if (sc->arg_parm)
1357 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001358 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1359 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001360 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001361 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001362 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001363 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001364 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001365 } else if (IS_ERR(sc->tp_format)) {
1366 /*
1367 * If we managed to read the tracepoint /format file, then we
1368 * may end up not having any args, like with gettid(), so only
1369 * print the raw args when we didn't manage to read it.
1370 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001371 int i = 0;
1372
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001373 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001374 /* special care for unaligned accesses */
1375 p = args + sizeof(unsigned long) * i;
1376 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001377 printed += scnprintf(bf + printed, size - printed,
1378 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001379 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001380 ++i;
1381 }
1382 }
1383
1384 return printed;
1385}
1386
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001387typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001388 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001389 struct perf_sample *sample);
1390
1391static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001392 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001393{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001394
1395 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001396
1397 /*
1398 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1399 * before that, leaving at a higher verbosity level till that is
1400 * explained. Reproduced with plain ftrace with:
1401 *
1402 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1403 * grep "NR -1 " /t/trace_pipe
1404 *
1405 * After generating some load on the machine.
1406 */
1407 if (verbose > 1) {
1408 static u64 n;
1409 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1410 id, perf_evsel__name(evsel), ++n);
1411 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001412 return NULL;
1413 }
1414
1415 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1416 trace__read_syscall_info(trace, id))
1417 goto out_cant_read;
1418
1419 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1420 goto out_cant_read;
1421
1422 return &trace->syscalls.table[id];
1423
1424out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001425 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001426 fprintf(trace->output, "Problems reading syscall %d", id);
1427 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1428 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1429 fputs(" information\n", trace->output);
1430 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001431 return NULL;
1432}
1433
David Ahernbf2575c2013-10-08 21:26:53 -06001434static void thread__update_stats(struct thread_trace *ttrace,
1435 int id, struct perf_sample *sample)
1436{
1437 struct int_node *inode;
1438 struct stats *stats;
1439 u64 duration = 0;
1440
1441 inode = intlist__findnew(ttrace->syscall_stats, id);
1442 if (inode == NULL)
1443 return;
1444
1445 stats = inode->priv;
1446 if (stats == NULL) {
1447 stats = malloc(sizeof(struct stats));
1448 if (stats == NULL)
1449 return;
1450 init_stats(stats);
1451 inode->priv = stats;
1452 }
1453
1454 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1455 duration = sample->time - ttrace->entry_time;
1456
1457 update_stats(stats, duration);
1458}
1459
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001460static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1461{
1462 struct thread_trace *ttrace;
1463 u64 duration;
1464 size_t printed;
1465
1466 if (trace->current == NULL)
1467 return 0;
1468
1469 ttrace = thread__priv(trace->current);
1470
1471 if (!ttrace->entry_pending)
1472 return 0;
1473
1474 duration = sample->time - ttrace->entry_time;
1475
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001476 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001477 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1478 ttrace->entry_pending = false;
1479
1480 return printed;
1481}
1482
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001483static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001484 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001485 struct perf_sample *sample)
1486{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001488 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001489 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001490 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001491 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001492 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001493 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001494
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001495 if (sc == NULL)
1496 return -1;
1497
David Ahern8fb598e2013-09-28 13:13:00 -06001498 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001499 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001500 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001501 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001502
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001503 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001504
1505 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001506 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001507 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001508 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001509 }
1510
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001511 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001512 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001513
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514 ttrace->entry_time = sample->time;
1515 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001516 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001517
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001518 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001519 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001521 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001522 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001523 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001524 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001525 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001526 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001527 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001528 /* See trace__vfs_getname & trace__sys_exit */
1529 ttrace->filename.pending_open = false;
1530 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001531
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001532 if (trace->current != thread) {
1533 thread__put(trace->current);
1534 trace->current = thread__get(thread);
1535 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001536 err = 0;
1537out_put:
1538 thread__put(thread);
1539 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001540}
1541
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001542static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1543 struct perf_sample *sample,
1544 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001545{
1546 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001547
1548 if (machine__resolve(trace->host, &al, sample) < 0 ||
1549 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1550 return -1;
1551
1552 return 0;
1553}
1554
1555static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1556{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001557 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001558 const unsigned int print_opts = EVSEL__PRINT_SYM |
1559 EVSEL__PRINT_DSO |
1560 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001561
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001562 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001563}
1564
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001565static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001566 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001567 struct perf_sample *sample)
1568{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001569 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001570 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001571 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001572 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001573 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001574 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001575 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001576
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001577 if (sc == NULL)
1578 return -1;
1579
David Ahern8fb598e2013-09-28 13:13:00 -06001580 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001581 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001582 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001583 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001584
David Ahernbf2575c2013-10-08 21:26:53 -06001585 if (trace->summary)
1586 thread__update_stats(ttrace, id, sample);
1587
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001588 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001589
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001590 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001591 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1592 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001593 ++trace->stats.vfs_getname;
1594 }
1595
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001596 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001597 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001598 if (trace__filter_duration(trace, duration))
1599 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001600 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001601 } else if (trace->duration_filter)
1602 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001603
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001604 if (sample->callchain) {
1605 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1606 if (callchain_ret == 0) {
1607 if (callchain_cursor.nr < trace->min_stack)
1608 goto out;
1609 callchain_ret = 1;
1610 }
1611 }
1612
David Ahernfd2eaba2013-11-12 09:31:15 -07001613 if (trace->summary_only)
1614 goto out;
1615
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001616 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001617
1618 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001619 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001620 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001621 fprintf(trace->output, " ... [");
1622 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1623 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001624 }
1625
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001626 if (sc->fmt == NULL) {
1627signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001628 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001629 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001630 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001631 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001632 *e = audit_errno_to_name(-ret);
1633
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001634 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001635 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001636 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001637 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001638 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001639 else if (sc->fmt->errpid) {
1640 struct thread *child = machine__find_thread(trace->host, ret, ret);
1641
1642 if (child != NULL) {
1643 fprintf(trace->output, ") = %ld", ret);
1644 if (child->comm_set)
1645 fprintf(trace->output, " (%s)", thread__comm_str(child));
1646 thread__put(child);
1647 }
1648 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001649 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001651 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001652
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001653 if (callchain_ret > 0)
1654 trace__fprintf_callchain(trace, sample);
1655 else if (callchain_ret < 0)
1656 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001657out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001658 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001659 err = 0;
1660out_put:
1661 thread__put(thread);
1662 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001663}
1664
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001665static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001666 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001667 struct perf_sample *sample)
1668{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001669 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1670 struct thread_trace *ttrace;
1671 size_t filename_len, entry_str_len, to_move;
1672 ssize_t remaining_space;
1673 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001674 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001675
1676 if (!thread)
1677 goto out;
1678
1679 ttrace = thread__priv(thread);
1680 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001681 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001682
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001683 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001684 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001685 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001686
1687 if (ttrace->filename.namelen < filename_len) {
1688 char *f = realloc(ttrace->filename.name, filename_len + 1);
1689
1690 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001691 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001692
1693 ttrace->filename.namelen = filename_len;
1694 ttrace->filename.name = f;
1695 }
1696
1697 strcpy(ttrace->filename.name, filename);
1698 ttrace->filename.pending_open = true;
1699
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001700 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001701 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001702
1703 entry_str_len = strlen(ttrace->entry_str);
1704 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1705 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001706 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001707
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001708 if (filename_len > (size_t)remaining_space) {
1709 filename += filename_len - remaining_space;
1710 filename_len = remaining_space;
1711 }
1712
1713 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1714 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1715 memmove(pos + filename_len, pos, to_move);
1716 memcpy(pos, filename, filename_len);
1717
1718 ttrace->filename.ptr = 0;
1719 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001720out_put:
1721 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001722out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001723 return 0;
1724}
1725
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001726static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001727 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001728 struct perf_sample *sample)
1729{
1730 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1731 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001732 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001733 sample->pid,
1734 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001735 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001736
1737 if (ttrace == NULL)
1738 goto out_dump;
1739
1740 ttrace->runtime_ms += runtime_ms;
1741 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001742out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001743 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001744 return 0;
1745
1746out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001747 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001748 evsel->name,
1749 perf_evsel__strval(evsel, sample, "comm"),
1750 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1751 runtime,
1752 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001753 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001754}
1755
Wang Nan1d6c9402016-02-26 09:31:55 +00001756static void bpf_output__printer(enum binary_printer_ops op,
1757 unsigned int val, void *extra)
1758{
1759 FILE *output = extra;
1760 unsigned char ch = (unsigned char)val;
1761
1762 switch (op) {
1763 case BINARY_PRINT_CHAR_DATA:
1764 fprintf(output, "%c", isprint(ch) ? ch : '.');
1765 break;
1766 case BINARY_PRINT_DATA_BEGIN:
1767 case BINARY_PRINT_LINE_BEGIN:
1768 case BINARY_PRINT_ADDR:
1769 case BINARY_PRINT_NUM_DATA:
1770 case BINARY_PRINT_NUM_PAD:
1771 case BINARY_PRINT_SEP:
1772 case BINARY_PRINT_CHAR_PAD:
1773 case BINARY_PRINT_LINE_END:
1774 case BINARY_PRINT_DATA_END:
1775 default:
1776 break;
1777 }
1778}
1779
1780static void bpf_output__fprintf(struct trace *trace,
1781 struct perf_sample *sample)
1782{
1783 print_binary(sample->raw_data, sample->raw_size, 8,
1784 bpf_output__printer, trace->output);
1785}
1786
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001787static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1788 union perf_event *event __maybe_unused,
1789 struct perf_sample *sample)
1790{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001791 int callchain_ret = 0;
1792
1793 if (sample->callchain) {
1794 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1795 if (callchain_ret == 0) {
1796 if (callchain_cursor.nr < trace->min_stack)
1797 goto out;
1798 callchain_ret = 1;
1799 }
1800 }
1801
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001802 trace__printf_interrupted_entry(trace, sample);
1803 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001804
1805 if (trace->trace_syscalls)
1806 fprintf(trace->output, "( ): ");
1807
1808 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001809
Wang Nan1d6c9402016-02-26 09:31:55 +00001810 if (perf_evsel__is_bpf_output(evsel)) {
1811 bpf_output__fprintf(trace, sample);
1812 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001813 event_format__fprintf(evsel->tp_format, sample->cpu,
1814 sample->raw_data, sample->raw_size,
1815 trace->output);
1816 }
1817
1818 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001819
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001820 if (callchain_ret > 0)
1821 trace__fprintf_callchain(trace, sample);
1822 else if (callchain_ret < 0)
1823 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1824out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001825 return 0;
1826}
1827
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001828static void print_location(FILE *f, struct perf_sample *sample,
1829 struct addr_location *al,
1830 bool print_dso, bool print_sym)
1831{
1832
Namhyung Kimbb963e12017-02-17 17:17:38 +09001833 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001834 fprintf(f, "%s@", al->map->dso->long_name);
1835
Namhyung Kimbb963e12017-02-17 17:17:38 +09001836 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001837 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001838 al->addr - al->sym->start);
1839 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001840 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001841 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001842 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001843}
1844
1845static int trace__pgfault(struct trace *trace,
1846 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001847 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001848 struct perf_sample *sample)
1849{
1850 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001851 struct addr_location al;
1852 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001853 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001854 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001855 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001856
1857 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001858
1859 if (sample->callchain) {
1860 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1861 if (callchain_ret == 0) {
1862 if (callchain_cursor.nr < trace->min_stack)
1863 goto out_put;
1864 callchain_ret = 1;
1865 }
1866 }
1867
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001868 ttrace = thread__trace(thread, trace->output);
1869 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001870 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001871
1872 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1873 ttrace->pfmaj++;
1874 else
1875 ttrace->pfmin++;
1876
1877 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001878 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001879
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001880 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001881 sample->ip, &al);
1882
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001883 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001884
1885 fprintf(trace->output, "%sfault [",
1886 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1887 "maj" : "min");
1888
1889 print_location(trace->output, sample, &al, false, true);
1890
1891 fprintf(trace->output, "] => ");
1892
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001893 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001894 sample->addr, &al);
1895
1896 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001897 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001898 MAP__FUNCTION, sample->addr, &al);
1899
1900 if (al.map)
1901 map_type = 'x';
1902 else
1903 map_type = '?';
1904 }
1905
1906 print_location(trace->output, sample, &al, true, false);
1907
1908 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001909
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001910 if (callchain_ret > 0)
1911 trace__fprintf_callchain(trace, sample);
1912 else if (callchain_ret < 0)
1913 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001914out:
1915 err = 0;
1916out_put:
1917 thread__put(thread);
1918 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001919}
1920
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001921static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001922 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001923 struct perf_sample *sample)
1924{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001925 /*
1926 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1927 * and don't use sample->time unconditionally, we may end up having
1928 * some other event in the future without PERF_SAMPLE_TIME for good
1929 * reason, i.e. we may not be interested in its timestamps, just in
1930 * it taking place, picking some piece of information when it
1931 * appears in our event stream (vfs_getname comes to mind).
1932 */
1933 if (trace->base_time == 0 && !trace->full_time &&
1934 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001935 trace->base_time = sample->time;
1936}
1937
David Ahern6810fc92013-08-28 22:29:52 -06001938static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001939 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001940 struct perf_sample *sample,
1941 struct perf_evsel *evsel,
1942 struct machine *machine __maybe_unused)
1943{
1944 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001945 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001946 int err = 0;
1947
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001948 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001949
David Ahernaa07df62016-11-25 09:29:52 -07001950 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1951 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001952 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06001953
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001954 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001955
David Ahern31605652013-12-04 19:41:41 -07001956 if (handler) {
1957 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001958 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001959 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001960out:
1961 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06001962 return err;
1963}
1964
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001965static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001966{
1967 unsigned int rec_argc, i, j;
1968 const char **rec_argv;
1969 const char * const record_args[] = {
1970 "record",
1971 "-R",
1972 "-m", "1024",
1973 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001974 };
1975
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001976 const char * const sc_args[] = { "-e", };
1977 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1978 const char * const majpf_args[] = { "-e", "major-faults" };
1979 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1980 const char * const minpf_args[] = { "-e", "minor-faults" };
1981 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1982
David Ahern9aca7f12013-12-04 19:41:39 -07001983 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001984 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1985 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001986 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1987
1988 if (rec_argv == NULL)
1989 return -ENOMEM;
1990
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001991 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001992 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001993 rec_argv[j++] = record_args[i];
1994
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001995 if (trace->trace_syscalls) {
1996 for (i = 0; i < sc_args_nr; i++)
1997 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06001998
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001999 /* event string may be different for older kernels - e.g., RHEL6 */
2000 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2001 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2002 else if (is_valid_tracepoint("syscalls:sys_enter"))
2003 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2004 else {
2005 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2006 return -1;
2007 }
David Ahern9aca7f12013-12-04 19:41:39 -07002008 }
David Ahern9aca7f12013-12-04 19:41:39 -07002009
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002010 if (trace->trace_pgfaults & TRACE_PFMAJ)
2011 for (i = 0; i < majpf_args_nr; i++)
2012 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002013
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002014 if (trace->trace_pgfaults & TRACE_PFMIN)
2015 for (i = 0; i < minpf_args_nr; i++)
2016 rec_argv[j++] = minpf_args[i];
2017
2018 for (i = 0; i < (unsigned int)argc; i++)
2019 rec_argv[j++] = argv[i];
2020
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002021 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002022}
2023
David Ahernbf2575c2013-10-08 21:26:53 -06002024static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2025
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002026static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002027{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002028 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002029
2030 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002031 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002032
2033 if (perf_evsel__field(evsel, "pathname") == NULL) {
2034 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002035 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002036 }
2037
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002038 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002039 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002040 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002041}
2042
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002043static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002044{
2045 struct perf_evsel *evsel;
2046 struct perf_event_attr attr = {
2047 .type = PERF_TYPE_SOFTWARE,
2048 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002049 };
2050
2051 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002052 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002053
2054 event_attr_init(&attr);
2055
2056 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002057 if (evsel)
2058 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002059
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002060 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002061}
2062
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002063static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2064{
2065 const u32 type = event->header.type;
2066 struct perf_evsel *evsel;
2067
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002068 if (type != PERF_RECORD_SAMPLE) {
2069 trace__process_event(trace, trace->host, event, sample);
2070 return;
2071 }
2072
2073 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2074 if (evsel == NULL) {
2075 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2076 return;
2077 }
2078
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002079 trace__set_base_time(trace, evsel, sample);
2080
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002081 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2082 sample->raw_data == NULL) {
2083 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2084 perf_evsel__name(evsel), sample->tid,
2085 sample->cpu, sample->raw_size);
2086 } else {
2087 tracepoint_handler handler = evsel->handler;
2088 handler(trace, evsel, event, sample);
2089 }
2090}
2091
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002092static int trace__add_syscall_newtp(struct trace *trace)
2093{
2094 int ret = -1;
2095 struct perf_evlist *evlist = trace->evlist;
2096 struct perf_evsel *sys_enter, *sys_exit;
2097
2098 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2099 if (sys_enter == NULL)
2100 goto out;
2101
2102 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2103 goto out_delete_sys_enter;
2104
2105 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2106 if (sys_exit == NULL)
2107 goto out_delete_sys_enter;
2108
2109 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2110 goto out_delete_sys_exit;
2111
2112 perf_evlist__add(evlist, sys_enter);
2113 perf_evlist__add(evlist, sys_exit);
2114
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002115 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002116 /*
2117 * We're interested only in the user space callchain
2118 * leading to the syscall, allow overriding that for
2119 * debugging reasons using --kernel_syscall_callchains
2120 */
2121 sys_exit->attr.exclude_callchain_kernel = 1;
2122 }
2123
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002124 trace->syscalls.events.sys_enter = sys_enter;
2125 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002126
2127 ret = 0;
2128out:
2129 return ret;
2130
2131out_delete_sys_exit:
2132 perf_evsel__delete_priv(sys_exit);
2133out_delete_sys_enter:
2134 perf_evsel__delete_priv(sys_enter);
2135 goto out;
2136}
2137
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002138static int trace__set_ev_qualifier_filter(struct trace *trace)
2139{
2140 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002141 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002142 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2143 trace->ev_qualifier_ids.nr,
2144 trace->ev_qualifier_ids.entries);
2145
2146 if (filter == NULL)
2147 goto out_enomem;
2148
Mathieu Poirier3541c032016-09-16 08:44:04 -06002149 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2150 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002151 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002152 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002153 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002154
2155 free(filter);
2156out:
2157 return err;
2158out_enomem:
2159 errno = ENOMEM;
2160 goto out;
2161}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002162
Namhyung Kimf15eb532012-10-05 14:02:16 +09002163static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002164{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002165 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002166 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002167 int err = -1, i;
2168 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002169 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002170 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002171
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002172 trace->live = true;
2173
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002174 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002175 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002176
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002177 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002178 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002179
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002180 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2181 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2182 if (pgfault_maj == NULL)
2183 goto out_error_mem;
2184 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002185 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002186
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002187 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2188 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2189 if (pgfault_min == NULL)
2190 goto out_error_mem;
2191 perf_evlist__add(evlist, pgfault_min);
2192 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002193
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002194 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002195 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2196 trace__sched_stat_runtime))
2197 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002198
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002199 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2200 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002201 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002202 goto out_delete_evlist;
2203 }
2204
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002205 err = trace__symbols_init(trace, evlist);
2206 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002207 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002208 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002209 }
2210
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002211 perf_evlist__config(evlist, &trace->opts, NULL);
2212
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002213 if (callchain_param.enabled) {
2214 bool use_identifier = false;
2215
2216 if (trace->syscalls.events.sys_exit) {
2217 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2218 &trace->opts, &callchain_param);
2219 use_identifier = true;
2220 }
2221
2222 if (pgfault_maj) {
2223 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2224 use_identifier = true;
2225 }
2226
2227 if (pgfault_min) {
2228 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2229 use_identifier = true;
2230 }
2231
2232 if (use_identifier) {
2233 /*
2234 * Now we have evsels with different sample_ids, use
2235 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2236 * from a fixed position in each ring buffer record.
2237 *
2238 * As of this the changeset introducing this comment, this
2239 * isn't strictly needed, as the fields that can come before
2240 * PERF_SAMPLE_ID are all used, but we'll probably disable
2241 * some of those for things like copying the payload of
2242 * pointer syscall arguments, and for vfs_getname we don't
2243 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2244 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2245 */
2246 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2247 perf_evlist__reset_sample_bit(evlist, ID);
2248 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002249 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002250
Namhyung Kimf15eb532012-10-05 14:02:16 +09002251 signal(SIGCHLD, sig_handler);
2252 signal(SIGINT, sig_handler);
2253
2254 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002255 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002256 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002257 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002258 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002259 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002260 }
2261 }
2262
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002263 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002264 if (err < 0)
2265 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002266
Wang Nanba504232016-02-26 09:31:54 +00002267 err = bpf__apply_obj_config();
2268 if (err) {
2269 char errbuf[BUFSIZ];
2270
2271 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2272 pr_err("ERROR: Apply config to BPF failed: %s\n",
2273 errbuf);
2274 goto out_error_open;
2275 }
2276
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002277 /*
2278 * Better not use !target__has_task() here because we need to cover the
2279 * case where no threads were specified in the command line, but a
2280 * workload was, and in that case we will fill in the thread_map when
2281 * we fork the workload in perf_evlist__prepare_workload.
2282 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002283 if (trace->filter_pids.nr > 0)
2284 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002285 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002286 err = perf_evlist__set_filter_pid(evlist, getpid());
2287
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002288 if (err < 0)
2289 goto out_error_mem;
2290
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002291 if (trace->ev_qualifier_ids.nr > 0) {
2292 err = trace__set_ev_qualifier_filter(trace);
2293 if (err < 0)
2294 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002295
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002296 pr_debug("event qualifier tracepoint filter: %s\n",
2297 trace->syscalls.events.sys_exit->filter);
2298 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002299
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002300 err = perf_evlist__apply_filters(evlist, &evsel);
2301 if (err < 0)
2302 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002303
Jiri Olsaf8850372013-11-28 17:57:22 +01002304 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002305 if (err < 0)
2306 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002307
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002308 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002309 perf_evlist__enable(evlist);
2310
Namhyung Kimf15eb532012-10-05 14:02:16 +09002311 if (forks)
2312 perf_evlist__start_workload(evlist);
2313
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002314 if (trace->opts.initial_delay) {
2315 usleep(trace->opts.initial_delay * 1000);
2316 perf_evlist__enable(evlist);
2317 }
2318
Jiri Olsae13798c2015-06-23 00:36:02 +02002319 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002320 evlist->threads->nr > 1 ||
2321 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002323 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002324
2325 for (i = 0; i < evlist->nr_mmaps; i++) {
2326 union perf_event *event;
2327
2328 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002329 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002330
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002331 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002332
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333 err = perf_evlist__parse_sample(evlist, event, &sample);
2334 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002335 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002336 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002337 }
2338
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002339 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002340next_event:
2341 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002342
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002343 if (interrupted)
2344 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002345
2346 if (done && !draining) {
2347 perf_evlist__disable(evlist);
2348 draining = true;
2349 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002350 }
2351 }
2352
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002353 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002354 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002355
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002356 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2357 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2358 draining = true;
2359
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002360 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002361 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002362 } else {
2363 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002364 }
2365
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002366out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002367 thread__zput(trace->current);
2368
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002369 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002370
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002371 if (!err) {
2372 if (trace->summary)
2373 trace__fprintf_thread_summary(trace, trace->output);
2374
2375 if (trace->show_tool_stats) {
2376 fprintf(trace->output, "Stats:\n "
2377 " vfs_getname : %" PRIu64 "\n"
2378 " proc_getname: %" PRIu64 "\n",
2379 trace->stats.vfs_getname,
2380 trace->stats.proc_getname);
2381 }
2382 }
David Ahernbf2575c2013-10-08 21:26:53 -06002383
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002384out_delete_evlist:
2385 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002386 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002387 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002388 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002389{
2390 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002391
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002392out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002393 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002394 goto out_error;
2395
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002396out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002397 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002398 goto out_error;
2399
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002400out_error_mmap:
2401 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2402 goto out_error;
2403
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002404out_error_open:
2405 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2406
2407out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002408 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302409 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002410
2411out_error_apply_filters:
2412 fprintf(trace->output,
2413 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2414 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002415 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002416 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002417}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002418out_error_mem:
2419 fprintf(trace->output, "Not enough memory to run!\n");
2420 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002421
2422out_errno:
2423 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2424 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002425}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002426
David Ahern6810fc92013-08-28 22:29:52 -06002427static int trace__replay(struct trace *trace)
2428{
2429 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002430 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002431 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002432 struct perf_data_file file = {
2433 .path = input_name,
2434 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002435 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002436 };
David Ahern6810fc92013-08-28 22:29:52 -06002437 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002438 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002439 int err = -1;
2440
2441 trace->tool.sample = trace__process_sample;
2442 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002443 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002444 trace->tool.comm = perf_event__process_comm;
2445 trace->tool.exit = perf_event__process_exit;
2446 trace->tool.fork = perf_event__process_fork;
2447 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302448 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002449 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302450 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002451
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002452 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002453 trace->tool.ordering_requires_timestamps = true;
2454
2455 /* add tid to output */
2456 trace->multiple_threads = true;
2457
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002458 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002459 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002460 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002461
David Ahernaa07df62016-11-25 09:29:52 -07002462 if (trace->opts.target.pid)
2463 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2464
2465 if (trace->opts.target.tid)
2466 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2467
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002468 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002469 goto out;
2470
David Ahern8fb598e2013-09-28 13:13:00 -06002471 trace->host = &session->machines.host;
2472
David Ahern6810fc92013-08-28 22:29:52 -06002473 err = perf_session__set_tracepoints_handlers(session, handlers);
2474 if (err)
2475 goto out;
2476
Namhyung Kim003824e2013-11-12 15:25:00 +09002477 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2478 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002479 /* older kernels have syscalls tp versus raw_syscalls */
2480 if (evsel == NULL)
2481 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2482 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002483
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002484 if (evsel &&
2485 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2486 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002487 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2488 goto out;
2489 }
2490
2491 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2492 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002493 if (evsel == NULL)
2494 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2495 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002496 if (evsel &&
2497 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2498 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002499 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002500 goto out;
2501 }
2502
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002503 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002504 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2505 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2506 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2507 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2508 evsel->handler = trace__pgfault;
2509 }
2510
David Ahern6810fc92013-08-28 22:29:52 -06002511 setup_pager();
2512
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002513 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002514 if (err)
2515 pr_err("Failed to process events, error %d", err);
2516
David Ahernbf2575c2013-10-08 21:26:53 -06002517 else if (trace->summary)
2518 trace__fprintf_thread_summary(trace, trace->output);
2519
David Ahern6810fc92013-08-28 22:29:52 -06002520out:
2521 perf_session__delete(session);
2522
2523 return err;
2524}
2525
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002526static size_t trace__fprintf_threads_header(FILE *fp)
2527{
2528 size_t printed;
2529
Pekka Enberg99ff7152013-11-12 16:42:14 +02002530 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002531
2532 return printed;
2533}
2534
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002535DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2536 struct stats *stats;
2537 double msecs;
2538 int syscall;
2539)
2540{
2541 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2542 struct stats *stats = source->priv;
2543
2544 entry->syscall = source->i;
2545 entry->stats = stats;
2546 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2547}
2548
David Ahernbf2575c2013-10-08 21:26:53 -06002549static size_t thread__dump_stats(struct thread_trace *ttrace,
2550 struct trace *trace, FILE *fp)
2551{
David Ahernbf2575c2013-10-08 21:26:53 -06002552 size_t printed = 0;
2553 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002554 struct rb_node *nd;
2555 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002556
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002557 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002558 return 0;
2559
2560 printed += fprintf(fp, "\n");
2561
Milian Wolff834fd462015-08-06 11:24:29 +02002562 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2563 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2564 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002565
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002566 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002567 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002568 if (stats) {
2569 double min = (double)(stats->min) / NSEC_PER_MSEC;
2570 double max = (double)(stats->max) / NSEC_PER_MSEC;
2571 double avg = avg_stats(stats);
2572 double pct;
2573 u64 n = (u64) stats->n;
2574
2575 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2576 avg /= NSEC_PER_MSEC;
2577
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002578 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002579 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002580 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002581 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002582 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002583 }
David Ahernbf2575c2013-10-08 21:26:53 -06002584 }
2585
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002586 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002587 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002588
2589 return printed;
2590}
2591
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002592static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002593{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002594 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002595 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002596 double ratio;
2597
2598 if (ttrace == NULL)
2599 return 0;
2600
2601 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2602
Pekka Enberg15e65c62013-11-14 18:43:30 +02002603 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002604 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002605 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002606 if (ttrace->pfmaj)
2607 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2608 if (ttrace->pfmin)
2609 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002610 if (trace->sched)
2611 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2612 else if (fputc('\n', fp) != EOF)
2613 ++printed;
2614
David Ahernbf2575c2013-10-08 21:26:53 -06002615 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002616
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002617 return printed;
2618}
David Ahern896cbb52013-09-28 13:12:59 -06002619
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002620static unsigned long thread__nr_events(struct thread_trace *ttrace)
2621{
2622 return ttrace ? ttrace->nr_events : 0;
2623}
2624
2625DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2626 struct thread *thread;
2627)
2628{
2629 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002630}
2631
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002632static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2633{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002634 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2635 size_t printed = trace__fprintf_threads_header(fp);
2636 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002637
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002638 if (threads == NULL) {
2639 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2640 return 0;
2641 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002642
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002643 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002644 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2645
2646 resort_rb__delete(threads);
2647
2648 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002649}
2650
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002651static int trace__set_duration(const struct option *opt, const char *str,
2652 int unset __maybe_unused)
2653{
2654 struct trace *trace = opt->value;
2655
2656 trace->duration_filter = atof(str);
2657 return 0;
2658}
2659
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002660static int trace__set_filter_pids(const struct option *opt, const char *str,
2661 int unset __maybe_unused)
2662{
2663 int ret = -1;
2664 size_t i;
2665 struct trace *trace = opt->value;
2666 /*
2667 * FIXME: introduce a intarray class, plain parse csv and create a
2668 * { int nr, int entries[] } struct...
2669 */
2670 struct intlist *list = intlist__new(str);
2671
2672 if (list == NULL)
2673 return -1;
2674
2675 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2676 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2677
2678 if (trace->filter_pids.entries == NULL)
2679 goto out;
2680
2681 trace->filter_pids.entries[0] = getpid();
2682
2683 for (i = 1; i < trace->filter_pids.nr; ++i)
2684 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2685
2686 intlist__delete(list);
2687 ret = 0;
2688out:
2689 return ret;
2690}
2691
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002692static int trace__open_output(struct trace *trace, const char *filename)
2693{
2694 struct stat st;
2695
2696 if (!stat(filename, &st) && st.st_size) {
2697 char oldname[PATH_MAX];
2698
2699 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2700 unlink(oldname);
2701 rename(filename, oldname);
2702 }
2703
2704 trace->output = fopen(filename, "w");
2705
2706 return trace->output == NULL ? -errno : 0;
2707}
2708
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002709static int parse_pagefaults(const struct option *opt, const char *str,
2710 int unset __maybe_unused)
2711{
2712 int *trace_pgfaults = opt->value;
2713
2714 if (strcmp(str, "all") == 0)
2715 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2716 else if (strcmp(str, "maj") == 0)
2717 *trace_pgfaults |= TRACE_PFMAJ;
2718 else if (strcmp(str, "min") == 0)
2719 *trace_pgfaults |= TRACE_PFMIN;
2720 else
2721 return -1;
2722
2723 return 0;
2724}
2725
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002726static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2727{
2728 struct perf_evsel *evsel;
2729
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002730 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002731 evsel->handler = handler;
2732}
2733
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002734/*
2735 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2736 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2737 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2738 *
2739 * It'd be better to introduce a parse_options() variant that would return a
2740 * list with the terms it didn't match to an event...
2741 */
2742static int trace__parse_events_option(const struct option *opt, const char *str,
2743 int unset __maybe_unused)
2744{
2745 struct trace *trace = (struct trace *)opt->value;
2746 const char *s = str;
2747 char *sep = NULL, *lists[2] = { NULL, NULL, };
2748 int len = strlen(str), err = -1, list;
2749 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2750 char group_name[PATH_MAX];
2751
2752 if (strace_groups_dir == NULL)
2753 return -1;
2754
2755 if (*s == '!') {
2756 ++s;
2757 trace->not_ev_qualifier = true;
2758 }
2759
2760 while (1) {
2761 if ((sep = strchr(s, ',')) != NULL)
2762 *sep = '\0';
2763
2764 list = 0;
2765 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2766 list = 1;
2767 } else {
2768 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2769 if (access(group_name, R_OK) == 0)
2770 list = 1;
2771 }
2772
2773 if (lists[list]) {
2774 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2775 } else {
2776 lists[list] = malloc(len);
2777 if (lists[list] == NULL)
2778 goto out;
2779 strcpy(lists[list], s);
2780 }
2781
2782 if (!sep)
2783 break;
2784
2785 *sep = ',';
2786 s = sep + 1;
2787 }
2788
2789 if (lists[1] != NULL) {
2790 struct strlist_config slist_config = {
2791 .dirname = strace_groups_dir,
2792 };
2793
2794 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2795 if (trace->ev_qualifier == NULL) {
2796 fputs("Not enough memory to parse event qualifier", trace->output);
2797 goto out;
2798 }
2799
2800 if (trace__validate_ev_qualifier(trace))
2801 goto out;
2802 }
2803
2804 err = 0;
2805
2806 if (lists[0]) {
2807 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2808 "event selector. use 'perf list' to list available events",
2809 parse_events_option);
2810 err = parse_events_option(&o, lists[0], 0);
2811 }
2812out:
2813 if (sep)
2814 *sep = ',';
2815
2816 return err;
2817}
2818
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002819int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002820{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002821 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002822 "perf trace [<options>] [<command>]",
2823 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002824 "perf trace record [<options>] [<command>]",
2825 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002826 NULL
2827 };
2828 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002829 .syscalls = {
2830 . max = -1,
2831 },
2832 .opts = {
2833 .target = {
2834 .uid = UINT_MAX,
2835 .uses_mmap = true,
2836 },
2837 .user_freq = UINT_MAX,
2838 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002839 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002840 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002841 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002842 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002843 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002844 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002845 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002846 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002847 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002848 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002849 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002850 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002851 OPT_CALLBACK('e', "event", &trace, "event",
2852 "event/syscall selector. use 'perf list' to list available events",
2853 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002854 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2855 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002856 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002857 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2858 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002859 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002860 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002861 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2862 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002863 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002864 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002865 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2866 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002867 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002868 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002869 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002870 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002871 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002872 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002873 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2874 "number of mmap data pages",
2875 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002876 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002877 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002878 OPT_CALLBACK(0, "duration", &trace, "float",
2879 "show only events with duration > N.M ms",
2880 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002881 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002882 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002883 OPT_BOOLEAN('T', "time", &trace.full_time,
2884 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002885 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2886 "Show only syscall summary with statistics"),
2887 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2888 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002889 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2890 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002891 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002892 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002893 OPT_CALLBACK(0, "call-graph", &trace.opts,
2894 "record_mode[,record_size]", record_callchain_help,
2895 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002896 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2897 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002898 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2899 "Set the minimum stack depth when parsing the callchain, "
2900 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002901 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2902 "Set the maximum stack depth when parsing the callchain, "
2903 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002904 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002905 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2906 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002907 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2908 "ms to wait before starting measurement after program "
2909 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002910 OPT_END()
2911 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002912 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002913 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002914 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002915 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002916 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002917
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002918 signal(SIGSEGV, sighandler_dump_stack);
2919 signal(SIGFPE, sighandler_dump_stack);
2920
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002921 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002922 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002923
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002924 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002925 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002926 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002927 goto out;
2928 }
2929
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002930 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2931 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002932
Wang Nand7888572016-04-08 15:07:24 +00002933 err = bpf__setup_stdout(trace.evlist);
2934 if (err) {
2935 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2936 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2937 goto out;
2938 }
2939
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002940 err = -1;
2941
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002942 if (trace.trace_pgfaults) {
2943 trace.opts.sample_address = true;
2944 trace.opts.sample_time = true;
2945 }
2946
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002947 if (trace.opts.mmap_pages == UINT_MAX)
2948 mmap_pages_user_set = false;
2949
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002950 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002951 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002952 max_stack_user_set = false;
2953 }
2954
2955#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002956 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002957 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2958#endif
2959
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002960 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002961 if (!mmap_pages_user_set && geteuid() == 0)
2962 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2963
Milian Wolff566a0882016-04-08 13:34:15 +02002964 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002965 }
Milian Wolff566a0882016-04-08 13:34:15 +02002966
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002967 if (trace.evlist->nr_entries > 0)
2968 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2969
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002970 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2971 return trace__record(&trace, argc-1, &argv[1]);
2972
2973 /* summary_only implies summary option, but don't overwrite summary if set */
2974 if (trace.summary_only)
2975 trace.summary = trace.summary_only;
2976
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002977 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2978 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002979 pr_err("Please specify something to trace.\n");
2980 return -1;
2981 }
2982
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002983 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002984 pr_err("The -e option can't be used with --no-syscalls.\n");
2985 goto out;
2986 }
2987
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002988 if (output_name != NULL) {
2989 err = trace__open_output(&trace, output_name);
2990 if (err < 0) {
2991 perror("failed to create output file");
2992 goto out;
2993 }
2994 }
2995
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002996 trace.open_id = syscalltbl__id(trace.sctbl, "open");
2997
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03002998 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002999 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003000 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003001 fprintf(trace.output, "%s", bf);
3002 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003003 }
3004
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003005 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003006 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003007 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003008 fprintf(trace.output, "%s", bf);
3009 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003010 }
3011
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003012 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003013 trace.opts.target.system_wide = true;
3014
David Ahern6810fc92013-08-28 22:29:52 -06003015 if (input_name)
3016 err = trace__replay(&trace);
3017 else
3018 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003019
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003020out_close:
3021 if (output_name != NULL)
3022 fclose(trace.output);
3023out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003024 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003025}