blob: d014350adc526722da3a12f29421cd6d3c00f4af [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 Melo5ab8c682017-04-25 15:30:47 -030024#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030025#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060026#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030027#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030028#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060029#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030030#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060031#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030032#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060033#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030034#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060035#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030036#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010037#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070038#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000039#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020040#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030041#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030042#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030043#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030044#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030045
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030046#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030047#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030048#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030049#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030050#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030052#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020053#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030054#include <linux/filter.h>
55#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030060
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030061#include "sane_ctype.h"
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef O_CLOEXEC
64# define O_CLOEXEC 02000000
65#endif
66
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030067struct trace {
68 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030069 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030070 struct {
71 int max;
72 struct syscall *table;
73 struct {
74 struct perf_evsel *sys_enter,
75 *sys_exit;
76 } events;
77 } syscalls;
78 struct record_opts opts;
79 struct perf_evlist *evlist;
80 struct machine *host;
81 struct thread *current;
82 u64 base_time;
83 FILE *output;
84 unsigned long nr_events;
85 struct strlist *ev_qualifier;
86 struct {
87 size_t nr;
88 int *entries;
89 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030090 struct {
91 size_t nr;
92 pid_t *entries;
93 } filter_pids;
94 double duration_filter;
95 double runtime_ms;
96 struct {
97 u64 vfs_getname,
98 proc_getname;
99 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300100 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300101 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300102 bool not_ev_qualifier;
103 bool live;
104 bool full_time;
105 bool sched;
106 bool multiple_threads;
107 bool summary;
108 bool summary_only;
109 bool show_comm;
110 bool show_tool_stats;
111 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300112 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300113 bool force;
114 bool vfs_getname;
115 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300116 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300118
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300119struct tp_field {
120 int offset;
121 union {
122 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
123 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
124 };
125};
126
127#define TP_UINT_FIELD(bits) \
128static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
129{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500130 u##bits value; \
131 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
132 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300133}
134
135TP_UINT_FIELD(8);
136TP_UINT_FIELD(16);
137TP_UINT_FIELD(32);
138TP_UINT_FIELD(64);
139
140#define TP_UINT_FIELD__SWAPPED(bits) \
141static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
142{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500143 u##bits value; \
144 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300145 return bswap_##bits(value);\
146}
147
148TP_UINT_FIELD__SWAPPED(16);
149TP_UINT_FIELD__SWAPPED(32);
150TP_UINT_FIELD__SWAPPED(64);
151
152static int tp_field__init_uint(struct tp_field *field,
153 struct format_field *format_field,
154 bool needs_swap)
155{
156 field->offset = format_field->offset;
157
158 switch (format_field->size) {
159 case 1:
160 field->integer = tp_field__u8;
161 break;
162 case 2:
163 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
164 break;
165 case 4:
166 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
167 break;
168 case 8:
169 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
170 break;
171 default:
172 return -1;
173 }
174
175 return 0;
176}
177
178static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
179{
180 return sample->raw_data + field->offset;
181}
182
183static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
184{
185 field->offset = format_field->offset;
186 field->pointer = tp_field__ptr;
187 return 0;
188}
189
190struct syscall_tp {
191 struct tp_field id;
192 union {
193 struct tp_field args, ret;
194 };
195};
196
197static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
198 struct tp_field *field,
199 const char *name)
200{
201 struct format_field *format_field = perf_evsel__field(evsel, name);
202
203 if (format_field == NULL)
204 return -1;
205
206 return tp_field__init_uint(field, format_field, evsel->needs_swap);
207}
208
209#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
210 ({ struct syscall_tp *sc = evsel->priv;\
211 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
212
213static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
214 struct tp_field *field,
215 const char *name)
216{
217 struct format_field *format_field = perf_evsel__field(evsel, name);
218
219 if (format_field == NULL)
220 return -1;
221
222 return tp_field__init_ptr(field, format_field);
223}
224
225#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
226 ({ struct syscall_tp *sc = evsel->priv;\
227 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
228
229static void perf_evsel__delete_priv(struct perf_evsel *evsel)
230{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300231 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300232 perf_evsel__delete(evsel);
233}
234
Namhyung Kim96695d42013-11-12 08:51:45 -0300235static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
236{
237 evsel->priv = malloc(sizeof(struct syscall_tp));
238 if (evsel->priv != NULL) {
239 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
240 goto out_delete;
241
242 evsel->handler = handler;
243 return 0;
244 }
245
246 return -ENOMEM;
247
248out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300249 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300250 return -ENOENT;
251}
252
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300253static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300254{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300255 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300256
David Ahern9aca7f12013-12-04 19:41:39 -0700257 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200258 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700259 evsel = perf_evsel__newtp("syscalls", direction);
260
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200261 if (IS_ERR(evsel))
262 return NULL;
263
264 if (perf_evsel__init_syscall_tp(evsel, handler))
265 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300266
267 return evsel;
268
269out_delete:
270 perf_evsel__delete_priv(evsel);
271 return NULL;
272}
273
274#define perf_evsel__sc_tp_uint(evsel, name, sample) \
275 ({ struct syscall_tp *fields = evsel->priv; \
276 fields->name.integer(&fields->name, sample); })
277
278#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
279 ({ struct syscall_tp *fields = evsel->priv; \
280 fields->name.pointer(&fields->name, sample); })
281
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300283 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300284 int nr_entries;
285 const char **entries;
286};
287
288#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
289 .nr_entries = ARRAY_SIZE(array), \
290 .entries = array, \
291}
292
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300293#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
294 .offset = off, \
295 .nr_entries = ARRAY_SIZE(array), \
296 .entries = array, \
297}
298
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300299static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
300 const char *intfmt,
301 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300304 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305
306 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300307 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300308
309 return scnprintf(bf, size, "%s", sa->entries[idx]);
310}
311
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300312static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
313 struct syscall_arg *arg)
314{
315 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
316}
317
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300318#define SCA_STRARRAY syscall_arg__scnprintf_strarray
319
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300320#if defined(__i386__) || defined(__x86_64__)
321/*
322 * FIXME: Make this available to all arches as soon as the ioctl beautifier
323 * gets rewritten to support all arches.
324 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300325static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
326 struct syscall_arg *arg)
327{
328 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
329}
330
331#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300332#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300333
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300334static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
335 struct syscall_arg *arg);
336
337#define SCA_FD syscall_arg__scnprintf_fd
338
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300339#ifndef AT_FDCWD
340#define AT_FDCWD -100
341#endif
342
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300343static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
344 struct syscall_arg *arg)
345{
346 int fd = arg->val;
347
348 if (fd == AT_FDCWD)
349 return scnprintf(bf, size, "CWD");
350
351 return syscall_arg__scnprintf_fd(bf, size, arg);
352}
353
354#define SCA_FDAT syscall_arg__scnprintf_fd_at
355
356static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
357 struct syscall_arg *arg);
358
359#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
360
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300361static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300362 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300363{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300364 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300365}
366
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300367#define SCA_HEX syscall_arg__scnprintf_hex
368
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300369static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
370 struct syscall_arg *arg)
371{
372 return scnprintf(bf, size, "%d", arg->val);
373}
374
375#define SCA_INT syscall_arg__scnprintf_int
376
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300377static const char *bpf_cmd[] = {
378 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
379 "MAP_GET_NEXT_KEY", "PROG_LOAD",
380};
381static DEFINE_STRARRAY(bpf_cmd);
382
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300383static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
384static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300385
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300386static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
387static DEFINE_STRARRAY(itimers);
388
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300389static const char *keyctl_options[] = {
390 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
391 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
392 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
393 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
394 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
395};
396static DEFINE_STRARRAY(keyctl_options);
397
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300398static const char *whences[] = { "SET", "CUR", "END",
399#ifdef SEEK_DATA
400"DATA",
401#endif
402#ifdef SEEK_HOLE
403"HOLE",
404#endif
405};
406static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300407
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300408static const char *fcntl_cmds[] = {
409 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
410 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
411 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
412 "F_GETOWNER_UIDS",
413};
414static DEFINE_STRARRAY(fcntl_cmds);
415
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300416static const char *rlimit_resources[] = {
417 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
418 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
419 "RTTIME",
420};
421static DEFINE_STRARRAY(rlimit_resources);
422
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300423static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
424static DEFINE_STRARRAY(sighow);
425
David Ahern4f8c1b72013-09-22 19:45:00 -0600426static const char *clockid[] = {
427 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300428 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
429 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600430};
431static DEFINE_STRARRAY(clockid);
432
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300433static const char *socket_families[] = {
434 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
435 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
436 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
437 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
438 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
439 "ALG", "NFC", "VSOCK",
440};
441static DEFINE_STRARRAY(socket_families);
442
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300443static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
444 struct syscall_arg *arg)
445{
446 size_t printed = 0;
447 int mode = arg->val;
448
449 if (mode == F_OK) /* 0 */
450 return scnprintf(bf, size, "F");
451#define P_MODE(n) \
452 if (mode & n##_OK) { \
453 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
454 mode &= ~n##_OK; \
455 }
456
457 P_MODE(R);
458 P_MODE(W);
459 P_MODE(X);
460#undef P_MODE
461
462 if (mode)
463 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
464
465 return printed;
466}
467
468#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
469
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300470static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
471 struct syscall_arg *arg);
472
473#define SCA_FILENAME syscall_arg__scnprintf_filename
474
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300475static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
476 struct syscall_arg *arg)
477{
478 int printed = 0, flags = arg->val;
479
480#define P_FLAG(n) \
481 if (flags & O_##n) { \
482 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
483 flags &= ~O_##n; \
484 }
485
486 P_FLAG(CLOEXEC);
487 P_FLAG(NONBLOCK);
488#undef P_FLAG
489
490 if (flags)
491 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
492
493 return printed;
494}
495
496#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
497
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300498#if defined(__i386__) || defined(__x86_64__)
499/*
500 * FIXME: Make this available to all arches.
501 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300502#define TCGETS 0x5401
503
504static const char *tioctls[] = {
505 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
506 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
507 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
508 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
509 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
510 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
511 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
512 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
513 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
514 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
515 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
516 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
517 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
518 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
519 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
520};
521
522static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300523#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300524
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300525#ifndef GRND_NONBLOCK
526#define GRND_NONBLOCK 0x0001
527#endif
528#ifndef GRND_RANDOM
529#define GRND_RANDOM 0x0002
530#endif
531
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300532static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
533 struct syscall_arg *arg)
534{
535 int printed = 0, flags = arg->val;
536
537#define P_FLAG(n) \
538 if (flags & GRND_##n) { \
539 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
540 flags &= ~GRND_##n; \
541 }
542
543 P_FLAG(RANDOM);
544 P_FLAG(NONBLOCK);
545#undef P_FLAG
546
547 if (flags)
548 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
549
550 return printed;
551}
552
553#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
554
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300555#define STRARRAY(arg, name, array) \
556 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
557 .arg_parm = { [arg] = &strarray__##array, }
558
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300559#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300560#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300561#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300562#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300563#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300564#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300565#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300566#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300567#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300568#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300569#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300570#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300571#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300572#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300573
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300574static struct syscall_fmt {
575 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300576 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300577 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300578 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300579 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300580 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300581 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300582 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300583} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300584 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300585 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300586 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300587 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300588 { .name = "brk", .hexret = true,
589 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300590 { .name = "chdir", .errmsg = true, },
591 { .name = "chmod", .errmsg = true, },
592 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600593 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300594 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300595 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300596 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300597 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300598 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300599 { .name = "dup", .errmsg = true, },
600 { .name = "dup2", .errmsg = true, },
601 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300602 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300603 { .name = "eventfd2", .errmsg = true,
604 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300605 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300606 { .name = "fadvise64", .errmsg = true, },
607 { .name = "fallocate", .errmsg = true, },
608 { .name = "fchdir", .errmsg = true, },
609 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300610 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300611 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300612 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300613 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300614 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300615 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300616 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300617 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300618 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300619 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300620 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
621 { .name = "fsetxattr", .errmsg = true, },
622 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300623 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300624 { .name = "fstatfs", .errmsg = true, },
625 { .name = "fsync", .errmsg = true, },
626 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300627 { .name = "futex", .errmsg = true,
628 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300629 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300630 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300631 { .name = "getdents", .errmsg = true, },
632 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300633 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300634 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300635 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300636 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300637 { .name = "getrandom", .errmsg = true,
638 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300639 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300640 { .name = "getxattr", .errmsg = true, },
641 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300642 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300643 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300644#if defined(__i386__) || defined(__x86_64__)
645/*
646 * FIXME: Make this available to all arches.
647 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300648 [1] = SCA_STRHEXARRAY, /* cmd */
649 [2] = SCA_HEX, /* arg */ },
650 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300651#else
652 [2] = SCA_HEX, /* arg */ }, },
653#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300654 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300655 { .name = "kill", .errmsg = true,
656 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300657 { .name = "lchown", .errmsg = true, },
658 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300659 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300660 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300661 { .name = "listxattr", .errmsg = true, },
662 { .name = "llistxattr", .errmsg = true, },
663 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300664 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300665 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300666 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300667 { .name = "lsetxattr", .errmsg = true, },
668 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
669 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300670 { .name = "madvise", .errmsg = true,
671 .arg_scnprintf = { [0] = SCA_HEX, /* start */
672 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300673 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300674 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300675 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
676 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300677 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300678 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300679 { .name = "mlock", .errmsg = true,
680 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
681 { .name = "mlockall", .errmsg = true,
682 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300683 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300684 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300685 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300686 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300687 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300688 .arg_scnprintf = { [0] = SCA_HEX, /* start */
689 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300690 { .name = "mq_unlink", .errmsg = true,
691 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300692 { .name = "mremap", .hexret = true,
693 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300694 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300695 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300696 { .name = "munlock", .errmsg = true,
697 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300698 { .name = "munmap", .errmsg = true,
699 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300700 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300701 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300702 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300703 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300704 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300705 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300706 { .name = "open_by_handle_at", .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 Melo31cd3852013-09-02 16:40:40 -0300709 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300710 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
711 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300712 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300713 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300714 [3] = SCA_FD, /* group_fd */
715 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300716 { .name = "pipe2", .errmsg = true,
717 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300718 { .name = "poll", .errmsg = true, .timeout = true, },
719 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300720 { .name = "pread", .errmsg = true, .alias = "pread64", },
721 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300722 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300723 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
724 { .name = "pwritev", .errmsg = true, },
725 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300726 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300727 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300728 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300729 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300730 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300731 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300732 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300733 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300734 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300735 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300736 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300737 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300738 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300739 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300740 { .name = "rt_sigaction", .errmsg = true,
741 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300742 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300743 { .name = "rt_sigqueueinfo", .errmsg = true,
744 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
745 { .name = "rt_tgsigqueueinfo", .errmsg = true,
746 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300747 { .name = "sched_getattr", .errmsg = true, },
748 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300749 { .name = "sched_setscheduler", .errmsg = true,
750 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300751 { .name = "seccomp", .errmsg = true,
752 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
753 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300754 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300755 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300756 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300757 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300758 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300759 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300760 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300761 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300762 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300763 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300764 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300765 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300766 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300767 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300768 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
769 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300770 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300771 { .name = "socketpair", .errmsg = true,
772 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
773 [1] = SCA_SK_TYPE, /* type */ },
774 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300775 { .name = "stat", .errmsg = true, .alias = "newstat", },
776 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300777 { .name = "statx", .errmsg = true,
778 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
779 [2] = SCA_STATX_FLAGS, /* flags */
780 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300781 { .name = "swapoff", .errmsg = true,
782 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
783 { .name = "swapon", .errmsg = true,
784 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300785 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300786 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300787 { .name = "tgkill", .errmsg = true,
788 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
789 { .name = "tkill", .errmsg = true,
790 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300791 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300792 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300793 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300794 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
795 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300796 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300797 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
798 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300799 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300800 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300801 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300802 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300803 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300804 { .name = "write", .errmsg = true, },
805 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300806};
807
808static int syscall_fmt__cmp(const void *name, const void *fmtp)
809{
810 const struct syscall_fmt *fmt = fmtp;
811 return strcmp(name, fmt->name);
812}
813
814static struct syscall_fmt *syscall_fmt__find(const char *name)
815{
816 const int nmemb = ARRAY_SIZE(syscall_fmts);
817 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
818}
819
820struct syscall {
821 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300822 int nr_args;
823 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300824 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300825 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300826 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300827 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300828 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300829};
830
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300831/*
832 * We need to have this 'calculated' boolean because in some cases we really
833 * don't know what is the duration of a syscall, for instance, when we start
834 * a session and some threads are waiting for a syscall to finish, say 'poll',
835 * in which case all we can do is to print "( ? ) for duration and for the
836 * start timestamp.
837 */
838static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200839{
840 double duration = (double)t / NSEC_PER_MSEC;
841 size_t printed = fprintf(fp, "(");
842
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300843 if (!calculated)
844 printed += fprintf(fp, " ? ");
845 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200846 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
847 else if (duration >= 0.01)
848 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
849 else
850 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300851 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200852}
853
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300854/**
855 * filename.ptr: The filename char pointer that will be vfs_getname'd
856 * filename.entry_str_pos: Where to insert the string translated from
857 * filename.ptr by the vfs_getname tracepoint/kprobe.
858 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300859struct thread_trace {
860 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300861 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300862 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400863 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300864 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300865 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300866 struct {
867 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300868 short int entry_str_pos;
869 bool pending_open;
870 unsigned int namelen;
871 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300872 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300873 struct {
874 int max;
875 char **table;
876 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600877
878 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300879};
880
881static struct thread_trace *thread_trace__new(void)
882{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300883 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
884
885 if (ttrace)
886 ttrace->paths.max = -1;
887
David Ahernbf2575c2013-10-08 21:26:53 -0600888 ttrace->syscall_stats = intlist__new(NULL);
889
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300890 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300891}
892
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300893static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300894{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300895 struct thread_trace *ttrace;
896
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897 if (thread == NULL)
898 goto fail;
899
Namhyung Kim89dceb22014-10-06 09:46:03 +0900900 if (thread__priv(thread) == NULL)
901 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300902
Namhyung Kim89dceb22014-10-06 09:46:03 +0900903 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300904 goto fail;
905
Namhyung Kim89dceb22014-10-06 09:46:03 +0900906 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300907 ++ttrace->nr_events;
908
909 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300910fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300911 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912 "WARNING: not enough memory, dropping samples!\n");
913 return NULL;
914}
915
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400916#define TRACE_PFMAJ (1 << 0)
917#define TRACE_PFMIN (1 << 1)
918
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300919static const size_t trace__entry_str_size = 2048;
920
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300921static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300922{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900923 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300924
925 if (fd > ttrace->paths.max) {
926 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
927
928 if (npath == NULL)
929 return -1;
930
931 if (ttrace->paths.max != -1) {
932 memset(npath + ttrace->paths.max + 1, 0,
933 (fd - ttrace->paths.max) * sizeof(char *));
934 } else {
935 memset(npath, 0, (fd + 1) * sizeof(char *));
936 }
937
938 ttrace->paths.table = npath;
939 ttrace->paths.max = fd;
940 }
941
942 ttrace->paths.table[fd] = strdup(pathname);
943
944 return ttrace->paths.table[fd] != NULL ? 0 : -1;
945}
946
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300947static int thread__read_fd_path(struct thread *thread, int fd)
948{
949 char linkname[PATH_MAX], pathname[PATH_MAX];
950 struct stat st;
951 int ret;
952
953 if (thread->pid_ == thread->tid) {
954 scnprintf(linkname, sizeof(linkname),
955 "/proc/%d/fd/%d", thread->pid_, fd);
956 } else {
957 scnprintf(linkname, sizeof(linkname),
958 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
959 }
960
961 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
962 return -1;
963
964 ret = readlink(linkname, pathname, sizeof(pathname));
965
966 if (ret < 0 || ret > st.st_size)
967 return -1;
968
969 pathname[ret] = '\0';
970 return trace__set_fd_pathname(thread, fd, pathname);
971}
972
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300973static const char *thread__fd_path(struct thread *thread, int fd,
974 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900976 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977
978 if (ttrace == NULL)
979 return NULL;
980
981 if (fd < 0)
982 return NULL;
983
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300984 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300985 if (!trace->live)
986 return NULL;
987 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300988 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300989 return NULL;
990 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300991
992 return ttrace->paths.table[fd];
993}
994
995static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
996 struct syscall_arg *arg)
997{
998 int fd = arg->val;
999 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001000 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001001
1002 if (path)
1003 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1004
1005 return printed;
1006}
1007
1008static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1009 struct syscall_arg *arg)
1010{
1011 int fd = arg->val;
1012 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001013 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001014
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001015 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1016 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001017
1018 return printed;
1019}
1020
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001021static void thread__set_filename_pos(struct thread *thread, const char *bf,
1022 unsigned long ptr)
1023{
1024 struct thread_trace *ttrace = thread__priv(thread);
1025
1026 ttrace->filename.ptr = ptr;
1027 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1028}
1029
1030static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1031 struct syscall_arg *arg)
1032{
1033 unsigned long ptr = arg->val;
1034
1035 if (!arg->trace->vfs_getname)
1036 return scnprintf(bf, size, "%#x", ptr);
1037
1038 thread__set_filename_pos(arg->thread, bf, ptr);
1039 return 0;
1040}
1041
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001042static bool trace__filter_duration(struct trace *trace, double t)
1043{
1044 return t < (trace->duration_filter * NSEC_PER_MSEC);
1045}
1046
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001047static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001048{
1049 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1050
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001051 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001052}
1053
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001054/*
1055 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1056 * using ttrace->entry_time for a thread that receives a sys_exit without
1057 * first having received a sys_enter ("poll" issued before tracing session
1058 * starts, lost sys_enter exit due to ring buffer overflow).
1059 */
1060static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1061{
1062 if (tstamp > 0)
1063 return __trace__fprintf_tstamp(trace, tstamp, fp);
1064
1065 return fprintf(fp, " ? ");
1066}
1067
Namhyung Kimf15eb532012-10-05 14:02:16 +09001068static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001069static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001070
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001071static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001072{
1073 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001074 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001075}
1076
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001077static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001078 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001079{
1080 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001081 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001082
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001083 if (trace->multiple_threads) {
1084 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001085 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001086 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001087 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001088
1089 return printed;
1090}
1091
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001092static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001093 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094{
1095 int ret = 0;
1096
1097 switch (event->header.type) {
1098 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001099 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001101 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001102 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001103 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001104 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105 break;
1106 }
1107
1108 return ret;
1109}
1110
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001111static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001112 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001113 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001114 struct machine *machine)
1115{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001116 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001117 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001118}
1119
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001120static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1121{
1122 struct machine *machine = vmachine;
1123
1124 if (machine->kptr_restrict_warned)
1125 return NULL;
1126
1127 if (symbol_conf.kptr_restrict) {
1128 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1129 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1130 "Kernel samples will not be resolved.\n");
1131 machine->kptr_restrict_warned = true;
1132 return NULL;
1133 }
1134
1135 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1136}
1137
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001138static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1139{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001140 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001141
1142 if (err)
1143 return err;
1144
David Ahern8fb598e2013-09-28 13:13:00 -06001145 trace->host = machine__new_host();
1146 if (trace->host == NULL)
1147 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001149 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001150 return -errno;
1151
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001152 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001153 evlist->threads, trace__tool_process, false,
1154 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155 if (err)
1156 symbol__exit();
1157
1158 return err;
1159}
1160
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001161static int syscall__set_arg_fmts(struct syscall *sc)
1162{
1163 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001164 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001165
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001166 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001167 if (sc->arg_scnprintf == NULL)
1168 return -1;
1169
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001170 if (sc->fmt)
1171 sc->arg_parm = sc->fmt->arg_parm;
1172
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001173 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001174 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1175 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001176 else if (strcmp(field->type, "const char *") == 0 &&
1177 (strcmp(field->name, "filename") == 0 ||
1178 strcmp(field->name, "path") == 0 ||
1179 strcmp(field->name, "pathname") == 0))
1180 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001181 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001182 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001183 else if (strcmp(field->type, "pid_t") == 0)
1184 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001185 else if (strcmp(field->type, "umode_t") == 0)
1186 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001187 else if ((strcmp(field->type, "int") == 0 ||
1188 strcmp(field->type, "unsigned int") == 0 ||
1189 strcmp(field->type, "long") == 0) &&
1190 (len = strlen(field->name)) >= 2 &&
1191 strcmp(field->name + len - 2, "fd") == 0) {
1192 /*
1193 * /sys/kernel/tracing/events/syscalls/sys_enter*
1194 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1195 * 65 int
1196 * 23 unsigned int
1197 * 7 unsigned long
1198 */
1199 sc->arg_scnprintf[idx] = SCA_FD;
1200 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001201 ++idx;
1202 }
1203
1204 return 0;
1205}
1206
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001207static int trace__read_syscall_info(struct trace *trace, int id)
1208{
1209 char tp_name[128];
1210 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001211 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001212
1213 if (name == NULL)
1214 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001215
1216 if (id > trace->syscalls.max) {
1217 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1218
1219 if (nsyscalls == NULL)
1220 return -1;
1221
1222 if (trace->syscalls.max != -1) {
1223 memset(nsyscalls + trace->syscalls.max + 1, 0,
1224 (id - trace->syscalls.max) * sizeof(*sc));
1225 } else {
1226 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1227 }
1228
1229 trace->syscalls.table = nsyscalls;
1230 trace->syscalls.max = id;
1231 }
1232
1233 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001234 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001235
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001236 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001237
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001238 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001239 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001240
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001241 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001242 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001243 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001244 }
1245
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001246 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001247 return -1;
1248
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001249 sc->args = sc->tp_format->format.fields;
1250 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001251 /*
1252 * We need to check and discard the first variable '__syscall_nr'
1253 * or 'nr' that mean the syscall number. It is needless here.
1254 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1255 */
1256 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001257 sc->args = sc->args->next;
1258 --sc->nr_args;
1259 }
1260
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001261 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1262
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001263 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001264}
1265
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001266static int trace__validate_ev_qualifier(struct trace *trace)
1267{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001268 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001269 struct str_node *pos;
1270
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001271 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1272 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1273 sizeof(trace->ev_qualifier_ids.entries[0]));
1274
1275 if (trace->ev_qualifier_ids.entries == NULL) {
1276 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1277 trace->output);
1278 err = -EINVAL;
1279 goto out;
1280 }
1281
1282 i = 0;
1283
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001284 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001285 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001286 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001287
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001288 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001289 if (err == 0) {
1290 fputs("Error:\tInvalid syscall ", trace->output);
1291 err = -EINVAL;
1292 } else {
1293 fputs(", ", trace->output);
1294 }
1295
1296 fputs(sc, trace->output);
1297 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001298
1299 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001300 }
1301
1302 if (err < 0) {
1303 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1304 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001305 zfree(&trace->ev_qualifier_ids.entries);
1306 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001307 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001308out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001309 return err;
1310}
1311
David Ahern55d43bc2015-02-19 15:00:22 -05001312/*
1313 * args is to be interpreted as a series of longs but we need to handle
1314 * 8-byte unaligned accesses. args points to raw_data within the event
1315 * and raw_data is guaranteed to be 8-byte unaligned because it is
1316 * preceded by raw_size which is a u32. So we need to copy args to a temp
1317 * variable to read it. Most notably this avoids extended load instructions
1318 * on unaligned addresses
1319 */
1320
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001321static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001322 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001323 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001324{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001325 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001326 unsigned char *p;
1327 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001328
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001329 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001330 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001331 u8 bit = 1;
1332 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001333 .idx = 0,
1334 .mask = 0,
1335 .trace = trace,
1336 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001337 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001338
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001339 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001340 field = field->next, ++arg.idx, bit <<= 1) {
1341 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001342 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001343
1344 /* special care for unaligned accesses */
1345 p = args + sizeof(unsigned long) * arg.idx;
1346 memcpy(&val, p, sizeof(val));
1347
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001348 /*
1349 * Suppress this argument if its value is zero and
1350 * and we don't have a string associated in an
1351 * strarray for it.
1352 */
David Ahern55d43bc2015-02-19 15:00:22 -05001353 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001354 !(sc->arg_scnprintf &&
1355 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1356 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001357 continue;
1358
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001359 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001360 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001361 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001362 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001363 if (sc->arg_parm)
1364 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001365 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1366 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001367 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001368 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001369 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001370 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001372 } else if (IS_ERR(sc->tp_format)) {
1373 /*
1374 * If we managed to read the tracepoint /format file, then we
1375 * may end up not having any args, like with gettid(), so only
1376 * print the raw args when we didn't manage to read it.
1377 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001378 int i = 0;
1379
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001380 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001381 /* special care for unaligned accesses */
1382 p = args + sizeof(unsigned long) * i;
1383 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001384 printed += scnprintf(bf + printed, size - printed,
1385 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001386 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001387 ++i;
1388 }
1389 }
1390
1391 return printed;
1392}
1393
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001394typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001395 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001396 struct perf_sample *sample);
1397
1398static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001399 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001400{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001401
1402 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001403
1404 /*
1405 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1406 * before that, leaving at a higher verbosity level till that is
1407 * explained. Reproduced with plain ftrace with:
1408 *
1409 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1410 * grep "NR -1 " /t/trace_pipe
1411 *
1412 * After generating some load on the machine.
1413 */
1414 if (verbose > 1) {
1415 static u64 n;
1416 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1417 id, perf_evsel__name(evsel), ++n);
1418 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001419 return NULL;
1420 }
1421
1422 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1423 trace__read_syscall_info(trace, id))
1424 goto out_cant_read;
1425
1426 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1427 goto out_cant_read;
1428
1429 return &trace->syscalls.table[id];
1430
1431out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001432 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001433 fprintf(trace->output, "Problems reading syscall %d", id);
1434 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1435 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1436 fputs(" information\n", trace->output);
1437 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001438 return NULL;
1439}
1440
David Ahernbf2575c2013-10-08 21:26:53 -06001441static void thread__update_stats(struct thread_trace *ttrace,
1442 int id, struct perf_sample *sample)
1443{
1444 struct int_node *inode;
1445 struct stats *stats;
1446 u64 duration = 0;
1447
1448 inode = intlist__findnew(ttrace->syscall_stats, id);
1449 if (inode == NULL)
1450 return;
1451
1452 stats = inode->priv;
1453 if (stats == NULL) {
1454 stats = malloc(sizeof(struct stats));
1455 if (stats == NULL)
1456 return;
1457 init_stats(stats);
1458 inode->priv = stats;
1459 }
1460
1461 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1462 duration = sample->time - ttrace->entry_time;
1463
1464 update_stats(stats, duration);
1465}
1466
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001467static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1468{
1469 struct thread_trace *ttrace;
1470 u64 duration;
1471 size_t printed;
1472
1473 if (trace->current == NULL)
1474 return 0;
1475
1476 ttrace = thread__priv(trace->current);
1477
1478 if (!ttrace->entry_pending)
1479 return 0;
1480
1481 duration = sample->time - ttrace->entry_time;
1482
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001483 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001484 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1485 ttrace->entry_pending = false;
1486
1487 return printed;
1488}
1489
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001490static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001491 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001492 struct perf_sample *sample)
1493{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001494 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001495 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001496 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001497 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001498 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001499 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001500 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001501
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001502 if (sc == NULL)
1503 return -1;
1504
David Ahern8fb598e2013-09-28 13:13:00 -06001505 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001506 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001507 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001508 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001509
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001510 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001511
1512 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001513 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001514 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001515 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001516 }
1517
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001518 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001519 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001520
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001521 ttrace->entry_time = sample->time;
1522 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001523 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001524
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001525 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001526 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001527
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001528 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001529 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001530 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001531 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001532 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001533 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001534 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001535 /* See trace__vfs_getname & trace__sys_exit */
1536 ttrace->filename.pending_open = false;
1537 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001538
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001539 if (trace->current != thread) {
1540 thread__put(trace->current);
1541 trace->current = thread__get(thread);
1542 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001543 err = 0;
1544out_put:
1545 thread__put(thread);
1546 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001547}
1548
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001549static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1550 struct perf_sample *sample,
1551 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001552{
1553 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001554
1555 if (machine__resolve(trace->host, &al, sample) < 0 ||
1556 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1557 return -1;
1558
1559 return 0;
1560}
1561
1562static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1563{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001564 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001565 const unsigned int print_opts = EVSEL__PRINT_SYM |
1566 EVSEL__PRINT_DSO |
1567 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001568
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001569 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001570}
1571
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001572static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001573 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001574 struct perf_sample *sample)
1575{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001576 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001577 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001578 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001579 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001580 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001581 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001582 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001583
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001584 if (sc == NULL)
1585 return -1;
1586
David Ahern8fb598e2013-09-28 13:13:00 -06001587 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001588 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001589 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001590 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001591
David Ahernbf2575c2013-10-08 21:26:53 -06001592 if (trace->summary)
1593 thread__update_stats(ttrace, id, sample);
1594
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001595 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001596
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001597 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001598 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1599 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001600 ++trace->stats.vfs_getname;
1601 }
1602
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001603 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001604 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001605 if (trace__filter_duration(trace, duration))
1606 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001607 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001608 } else if (trace->duration_filter)
1609 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001610
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001611 if (sample->callchain) {
1612 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1613 if (callchain_ret == 0) {
1614 if (callchain_cursor.nr < trace->min_stack)
1615 goto out;
1616 callchain_ret = 1;
1617 }
1618 }
1619
David Ahernfd2eaba2013-11-12 09:31:15 -07001620 if (trace->summary_only)
1621 goto out;
1622
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001623 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001624
1625 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001626 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001627 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001628 fprintf(trace->output, " ... [");
1629 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1630 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001631 }
1632
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001633 if (sc->fmt == NULL) {
1634signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001635 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001636 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001637 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001638 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001639 *e = audit_errno_to_name(-ret);
1640
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001641 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001642 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001643 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001644 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001645 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001646 else if (sc->fmt->errpid) {
1647 struct thread *child = machine__find_thread(trace->host, ret, ret);
1648
1649 if (child != NULL) {
1650 fprintf(trace->output, ") = %ld", ret);
1651 if (child->comm_set)
1652 fprintf(trace->output, " (%s)", thread__comm_str(child));
1653 thread__put(child);
1654 }
1655 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001656 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001657
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001658 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001659
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001660 if (callchain_ret > 0)
1661 trace__fprintf_callchain(trace, sample);
1662 else if (callchain_ret < 0)
1663 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001664out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001665 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001666 err = 0;
1667out_put:
1668 thread__put(thread);
1669 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001670}
1671
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001672static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001673 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001674 struct perf_sample *sample)
1675{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001676 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1677 struct thread_trace *ttrace;
1678 size_t filename_len, entry_str_len, to_move;
1679 ssize_t remaining_space;
1680 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001681 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001682
1683 if (!thread)
1684 goto out;
1685
1686 ttrace = thread__priv(thread);
1687 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001688 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001689
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001690 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001691 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001692 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001693
1694 if (ttrace->filename.namelen < filename_len) {
1695 char *f = realloc(ttrace->filename.name, filename_len + 1);
1696
1697 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001698 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001699
1700 ttrace->filename.namelen = filename_len;
1701 ttrace->filename.name = f;
1702 }
1703
1704 strcpy(ttrace->filename.name, filename);
1705 ttrace->filename.pending_open = true;
1706
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001707 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001708 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001709
1710 entry_str_len = strlen(ttrace->entry_str);
1711 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1712 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001713 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001714
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001715 if (filename_len > (size_t)remaining_space) {
1716 filename += filename_len - remaining_space;
1717 filename_len = remaining_space;
1718 }
1719
1720 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1721 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1722 memmove(pos + filename_len, pos, to_move);
1723 memcpy(pos, filename, filename_len);
1724
1725 ttrace->filename.ptr = 0;
1726 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001727out_put:
1728 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001729out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001730 return 0;
1731}
1732
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001733static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001734 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001735 struct perf_sample *sample)
1736{
1737 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1738 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001739 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001740 sample->pid,
1741 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001742 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001743
1744 if (ttrace == NULL)
1745 goto out_dump;
1746
1747 ttrace->runtime_ms += runtime_ms;
1748 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001749out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001750 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001751 return 0;
1752
1753out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001754 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001755 evsel->name,
1756 perf_evsel__strval(evsel, sample, "comm"),
1757 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1758 runtime,
1759 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001760 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001761}
1762
Wang Nan1d6c9402016-02-26 09:31:55 +00001763static void bpf_output__printer(enum binary_printer_ops op,
1764 unsigned int val, void *extra)
1765{
1766 FILE *output = extra;
1767 unsigned char ch = (unsigned char)val;
1768
1769 switch (op) {
1770 case BINARY_PRINT_CHAR_DATA:
1771 fprintf(output, "%c", isprint(ch) ? ch : '.');
1772 break;
1773 case BINARY_PRINT_DATA_BEGIN:
1774 case BINARY_PRINT_LINE_BEGIN:
1775 case BINARY_PRINT_ADDR:
1776 case BINARY_PRINT_NUM_DATA:
1777 case BINARY_PRINT_NUM_PAD:
1778 case BINARY_PRINT_SEP:
1779 case BINARY_PRINT_CHAR_PAD:
1780 case BINARY_PRINT_LINE_END:
1781 case BINARY_PRINT_DATA_END:
1782 default:
1783 break;
1784 }
1785}
1786
1787static void bpf_output__fprintf(struct trace *trace,
1788 struct perf_sample *sample)
1789{
1790 print_binary(sample->raw_data, sample->raw_size, 8,
1791 bpf_output__printer, trace->output);
1792}
1793
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001794static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1795 union perf_event *event __maybe_unused,
1796 struct perf_sample *sample)
1797{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001798 int callchain_ret = 0;
1799
1800 if (sample->callchain) {
1801 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1802 if (callchain_ret == 0) {
1803 if (callchain_cursor.nr < trace->min_stack)
1804 goto out;
1805 callchain_ret = 1;
1806 }
1807 }
1808
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001809 trace__printf_interrupted_entry(trace, sample);
1810 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001811
1812 if (trace->trace_syscalls)
1813 fprintf(trace->output, "( ): ");
1814
1815 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001816
Wang Nan1d6c9402016-02-26 09:31:55 +00001817 if (perf_evsel__is_bpf_output(evsel)) {
1818 bpf_output__fprintf(trace, sample);
1819 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001820 event_format__fprintf(evsel->tp_format, sample->cpu,
1821 sample->raw_data, sample->raw_size,
1822 trace->output);
1823 }
1824
1825 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001826
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001827 if (callchain_ret > 0)
1828 trace__fprintf_callchain(trace, sample);
1829 else if (callchain_ret < 0)
1830 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1831out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001832 return 0;
1833}
1834
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001835static void print_location(FILE *f, struct perf_sample *sample,
1836 struct addr_location *al,
1837 bool print_dso, bool print_sym)
1838{
1839
Namhyung Kimbb963e12017-02-17 17:17:38 +09001840 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001841 fprintf(f, "%s@", al->map->dso->long_name);
1842
Namhyung Kimbb963e12017-02-17 17:17:38 +09001843 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001844 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001845 al->addr - al->sym->start);
1846 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001847 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001848 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001849 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001850}
1851
1852static int trace__pgfault(struct trace *trace,
1853 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001854 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001855 struct perf_sample *sample)
1856{
1857 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001858 struct addr_location al;
1859 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001860 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001861 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001862 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001863
1864 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001865
1866 if (sample->callchain) {
1867 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1868 if (callchain_ret == 0) {
1869 if (callchain_cursor.nr < trace->min_stack)
1870 goto out_put;
1871 callchain_ret = 1;
1872 }
1873 }
1874
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001875 ttrace = thread__trace(thread, trace->output);
1876 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001877 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001878
1879 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1880 ttrace->pfmaj++;
1881 else
1882 ttrace->pfmin++;
1883
1884 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001885 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001886
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001887 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888 sample->ip, &al);
1889
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001890 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001891
1892 fprintf(trace->output, "%sfault [",
1893 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1894 "maj" : "min");
1895
1896 print_location(trace->output, sample, &al, false, true);
1897
1898 fprintf(trace->output, "] => ");
1899
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001900 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001901 sample->addr, &al);
1902
1903 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001904 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001905 MAP__FUNCTION, sample->addr, &al);
1906
1907 if (al.map)
1908 map_type = 'x';
1909 else
1910 map_type = '?';
1911 }
1912
1913 print_location(trace->output, sample, &al, true, false);
1914
1915 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001916
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001917 if (callchain_ret > 0)
1918 trace__fprintf_callchain(trace, sample);
1919 else if (callchain_ret < 0)
1920 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001921out:
1922 err = 0;
1923out_put:
1924 thread__put(thread);
1925 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001926}
1927
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001928static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001929 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001930 struct perf_sample *sample)
1931{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001932 /*
1933 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1934 * and don't use sample->time unconditionally, we may end up having
1935 * some other event in the future without PERF_SAMPLE_TIME for good
1936 * reason, i.e. we may not be interested in its timestamps, just in
1937 * it taking place, picking some piece of information when it
1938 * appears in our event stream (vfs_getname comes to mind).
1939 */
1940 if (trace->base_time == 0 && !trace->full_time &&
1941 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001942 trace->base_time = sample->time;
1943}
1944
David Ahern6810fc92013-08-28 22:29:52 -06001945static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001946 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001947 struct perf_sample *sample,
1948 struct perf_evsel *evsel,
1949 struct machine *machine __maybe_unused)
1950{
1951 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001952 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001953 int err = 0;
1954
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001955 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001956
David Ahernaa07df62016-11-25 09:29:52 -07001957 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1958 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001959 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06001960
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001961 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001962
David Ahern31605652013-12-04 19:41:41 -07001963 if (handler) {
1964 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001965 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001966 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001967out:
1968 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06001969 return err;
1970}
1971
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001972static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001973{
1974 unsigned int rec_argc, i, j;
1975 const char **rec_argv;
1976 const char * const record_args[] = {
1977 "record",
1978 "-R",
1979 "-m", "1024",
1980 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001981 };
1982
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001983 const char * const sc_args[] = { "-e", };
1984 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1985 const char * const majpf_args[] = { "-e", "major-faults" };
1986 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1987 const char * const minpf_args[] = { "-e", "minor-faults" };
1988 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1989
David Ahern9aca7f12013-12-04 19:41:39 -07001990 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001991 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1992 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001993 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1994
1995 if (rec_argv == NULL)
1996 return -ENOMEM;
1997
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001998 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001999 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002000 rec_argv[j++] = record_args[i];
2001
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002002 if (trace->trace_syscalls) {
2003 for (i = 0; i < sc_args_nr; i++)
2004 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002005
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002006 /* event string may be different for older kernels - e.g., RHEL6 */
2007 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2008 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2009 else if (is_valid_tracepoint("syscalls:sys_enter"))
2010 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2011 else {
2012 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2013 return -1;
2014 }
David Ahern9aca7f12013-12-04 19:41:39 -07002015 }
David Ahern9aca7f12013-12-04 19:41:39 -07002016
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002017 if (trace->trace_pgfaults & TRACE_PFMAJ)
2018 for (i = 0; i < majpf_args_nr; i++)
2019 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002020
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002021 if (trace->trace_pgfaults & TRACE_PFMIN)
2022 for (i = 0; i < minpf_args_nr; i++)
2023 rec_argv[j++] = minpf_args[i];
2024
2025 for (i = 0; i < (unsigned int)argc; i++)
2026 rec_argv[j++] = argv[i];
2027
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002028 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002029}
2030
David Ahernbf2575c2013-10-08 21:26:53 -06002031static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2032
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002033static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002034{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002035 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002036
2037 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002038 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002039
2040 if (perf_evsel__field(evsel, "pathname") == NULL) {
2041 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002042 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002043 }
2044
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002045 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002046 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002047 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002048}
2049
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002050static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002051{
2052 struct perf_evsel *evsel;
2053 struct perf_event_attr attr = {
2054 .type = PERF_TYPE_SOFTWARE,
2055 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002056 };
2057
2058 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002059 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002060
2061 event_attr_init(&attr);
2062
2063 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002064 if (evsel)
2065 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002066
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002067 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002068}
2069
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002070static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2071{
2072 const u32 type = event->header.type;
2073 struct perf_evsel *evsel;
2074
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002075 if (type != PERF_RECORD_SAMPLE) {
2076 trace__process_event(trace, trace->host, event, sample);
2077 return;
2078 }
2079
2080 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2081 if (evsel == NULL) {
2082 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2083 return;
2084 }
2085
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002086 trace__set_base_time(trace, evsel, sample);
2087
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002088 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2089 sample->raw_data == NULL) {
2090 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2091 perf_evsel__name(evsel), sample->tid,
2092 sample->cpu, sample->raw_size);
2093 } else {
2094 tracepoint_handler handler = evsel->handler;
2095 handler(trace, evsel, event, sample);
2096 }
2097}
2098
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002099static int trace__add_syscall_newtp(struct trace *trace)
2100{
2101 int ret = -1;
2102 struct perf_evlist *evlist = trace->evlist;
2103 struct perf_evsel *sys_enter, *sys_exit;
2104
2105 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2106 if (sys_enter == NULL)
2107 goto out;
2108
2109 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2110 goto out_delete_sys_enter;
2111
2112 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2113 if (sys_exit == NULL)
2114 goto out_delete_sys_enter;
2115
2116 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2117 goto out_delete_sys_exit;
2118
2119 perf_evlist__add(evlist, sys_enter);
2120 perf_evlist__add(evlist, sys_exit);
2121
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002122 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002123 /*
2124 * We're interested only in the user space callchain
2125 * leading to the syscall, allow overriding that for
2126 * debugging reasons using --kernel_syscall_callchains
2127 */
2128 sys_exit->attr.exclude_callchain_kernel = 1;
2129 }
2130
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002131 trace->syscalls.events.sys_enter = sys_enter;
2132 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002133
2134 ret = 0;
2135out:
2136 return ret;
2137
2138out_delete_sys_exit:
2139 perf_evsel__delete_priv(sys_exit);
2140out_delete_sys_enter:
2141 perf_evsel__delete_priv(sys_enter);
2142 goto out;
2143}
2144
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002145static int trace__set_ev_qualifier_filter(struct trace *trace)
2146{
2147 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002148 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002149 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2150 trace->ev_qualifier_ids.nr,
2151 trace->ev_qualifier_ids.entries);
2152
2153 if (filter == NULL)
2154 goto out_enomem;
2155
Mathieu Poirier3541c032016-09-16 08:44:04 -06002156 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2157 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002158 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002159 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002160 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002161
2162 free(filter);
2163out:
2164 return err;
2165out_enomem:
2166 errno = ENOMEM;
2167 goto out;
2168}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002169
Namhyung Kimf15eb532012-10-05 14:02:16 +09002170static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002171{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002172 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002173 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002174 int err = -1, i;
2175 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002176 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002177 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002178
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002179 trace->live = true;
2180
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002181 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002182 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002183
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002184 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002185 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002186
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002187 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2188 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2189 if (pgfault_maj == NULL)
2190 goto out_error_mem;
2191 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002192 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002193
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002194 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2195 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2196 if (pgfault_min == NULL)
2197 goto out_error_mem;
2198 perf_evlist__add(evlist, pgfault_min);
2199 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002200
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002201 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002202 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2203 trace__sched_stat_runtime))
2204 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002205
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002206 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2207 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002208 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002209 goto out_delete_evlist;
2210 }
2211
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002212 err = trace__symbols_init(trace, evlist);
2213 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002214 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002215 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002216 }
2217
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002218 perf_evlist__config(evlist, &trace->opts, NULL);
2219
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002220 if (callchain_param.enabled) {
2221 bool use_identifier = false;
2222
2223 if (trace->syscalls.events.sys_exit) {
2224 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2225 &trace->opts, &callchain_param);
2226 use_identifier = true;
2227 }
2228
2229 if (pgfault_maj) {
2230 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2231 use_identifier = true;
2232 }
2233
2234 if (pgfault_min) {
2235 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2236 use_identifier = true;
2237 }
2238
2239 if (use_identifier) {
2240 /*
2241 * Now we have evsels with different sample_ids, use
2242 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2243 * from a fixed position in each ring buffer record.
2244 *
2245 * As of this the changeset introducing this comment, this
2246 * isn't strictly needed, as the fields that can come before
2247 * PERF_SAMPLE_ID are all used, but we'll probably disable
2248 * some of those for things like copying the payload of
2249 * pointer syscall arguments, and for vfs_getname we don't
2250 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2251 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2252 */
2253 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2254 perf_evlist__reset_sample_bit(evlist, ID);
2255 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002256 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002257
Namhyung Kimf15eb532012-10-05 14:02:16 +09002258 signal(SIGCHLD, sig_handler);
2259 signal(SIGINT, sig_handler);
2260
2261 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002262 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002263 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002264 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002265 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002266 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002267 }
2268 }
2269
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002270 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002271 if (err < 0)
2272 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002273
Wang Nanba504232016-02-26 09:31:54 +00002274 err = bpf__apply_obj_config();
2275 if (err) {
2276 char errbuf[BUFSIZ];
2277
2278 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2279 pr_err("ERROR: Apply config to BPF failed: %s\n",
2280 errbuf);
2281 goto out_error_open;
2282 }
2283
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002284 /*
2285 * Better not use !target__has_task() here because we need to cover the
2286 * case where no threads were specified in the command line, but a
2287 * workload was, and in that case we will fill in the thread_map when
2288 * we fork the workload in perf_evlist__prepare_workload.
2289 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002290 if (trace->filter_pids.nr > 0)
2291 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002292 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002293 err = perf_evlist__set_filter_pid(evlist, getpid());
2294
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002295 if (err < 0)
2296 goto out_error_mem;
2297
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002298 if (trace->ev_qualifier_ids.nr > 0) {
2299 err = trace__set_ev_qualifier_filter(trace);
2300 if (err < 0)
2301 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002302
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002303 pr_debug("event qualifier tracepoint filter: %s\n",
2304 trace->syscalls.events.sys_exit->filter);
2305 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002306
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002307 err = perf_evlist__apply_filters(evlist, &evsel);
2308 if (err < 0)
2309 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002310
Jiri Olsaf8850372013-11-28 17:57:22 +01002311 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002312 if (err < 0)
2313 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002314
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002315 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002316 perf_evlist__enable(evlist);
2317
Namhyung Kimf15eb532012-10-05 14:02:16 +09002318 if (forks)
2319 perf_evlist__start_workload(evlist);
2320
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002321 if (trace->opts.initial_delay) {
2322 usleep(trace->opts.initial_delay * 1000);
2323 perf_evlist__enable(evlist);
2324 }
2325
Jiri Olsae13798c2015-06-23 00:36:02 +02002326 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002327 evlist->threads->nr > 1 ||
2328 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002329again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002330 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002331
2332 for (i = 0; i < evlist->nr_mmaps; i++) {
2333 union perf_event *event;
2334
2335 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002336 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002337
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002338 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002339
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002340 err = perf_evlist__parse_sample(evlist, event, &sample);
2341 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002342 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002343 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002344 }
2345
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002346 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002347next_event:
2348 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002349
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002350 if (interrupted)
2351 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002352
2353 if (done && !draining) {
2354 perf_evlist__disable(evlist);
2355 draining = true;
2356 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002357 }
2358 }
2359
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002360 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002361 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002362
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002363 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2364 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2365 draining = true;
2366
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002367 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002368 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002369 } else {
2370 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002371 }
2372
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002373out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002374 thread__zput(trace->current);
2375
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002376 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002377
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002378 if (!err) {
2379 if (trace->summary)
2380 trace__fprintf_thread_summary(trace, trace->output);
2381
2382 if (trace->show_tool_stats) {
2383 fprintf(trace->output, "Stats:\n "
2384 " vfs_getname : %" PRIu64 "\n"
2385 " proc_getname: %" PRIu64 "\n",
2386 trace->stats.vfs_getname,
2387 trace->stats.proc_getname);
2388 }
2389 }
David Ahernbf2575c2013-10-08 21:26:53 -06002390
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002391out_delete_evlist:
2392 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002393 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002394 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002395 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002396{
2397 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002398
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002399out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002400 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002401 goto out_error;
2402
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002403out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002404 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002405 goto out_error;
2406
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002407out_error_mmap:
2408 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2409 goto out_error;
2410
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002411out_error_open:
2412 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2413
2414out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002415 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302416 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002417
2418out_error_apply_filters:
2419 fprintf(trace->output,
2420 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2421 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002422 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002423 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002424}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002425out_error_mem:
2426 fprintf(trace->output, "Not enough memory to run!\n");
2427 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002428
2429out_errno:
2430 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2431 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002432}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002433
David Ahern6810fc92013-08-28 22:29:52 -06002434static int trace__replay(struct trace *trace)
2435{
2436 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002437 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002438 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002439 struct perf_data_file file = {
2440 .path = input_name,
2441 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002442 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002443 };
David Ahern6810fc92013-08-28 22:29:52 -06002444 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002445 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002446 int err = -1;
2447
2448 trace->tool.sample = trace__process_sample;
2449 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002450 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002451 trace->tool.comm = perf_event__process_comm;
2452 trace->tool.exit = perf_event__process_exit;
2453 trace->tool.fork = perf_event__process_fork;
2454 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302455 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002456 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302457 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002458
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002459 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002460 trace->tool.ordering_requires_timestamps = true;
2461
2462 /* add tid to output */
2463 trace->multiple_threads = true;
2464
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002465 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002466 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002467 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002468
David Ahernaa07df62016-11-25 09:29:52 -07002469 if (trace->opts.target.pid)
2470 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2471
2472 if (trace->opts.target.tid)
2473 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2474
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002475 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002476 goto out;
2477
David Ahern8fb598e2013-09-28 13:13:00 -06002478 trace->host = &session->machines.host;
2479
David Ahern6810fc92013-08-28 22:29:52 -06002480 err = perf_session__set_tracepoints_handlers(session, handlers);
2481 if (err)
2482 goto out;
2483
Namhyung Kim003824e2013-11-12 15:25:00 +09002484 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2485 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002486 /* older kernels have syscalls tp versus raw_syscalls */
2487 if (evsel == NULL)
2488 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2489 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002490
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002491 if (evsel &&
2492 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2493 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002494 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2495 goto out;
2496 }
2497
2498 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2499 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002500 if (evsel == NULL)
2501 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2502 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002503 if (evsel &&
2504 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2505 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002506 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002507 goto out;
2508 }
2509
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002510 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002511 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2512 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2513 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2514 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2515 evsel->handler = trace__pgfault;
2516 }
2517
David Ahern6810fc92013-08-28 22:29:52 -06002518 setup_pager();
2519
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002520 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002521 if (err)
2522 pr_err("Failed to process events, error %d", err);
2523
David Ahernbf2575c2013-10-08 21:26:53 -06002524 else if (trace->summary)
2525 trace__fprintf_thread_summary(trace, trace->output);
2526
David Ahern6810fc92013-08-28 22:29:52 -06002527out:
2528 perf_session__delete(session);
2529
2530 return err;
2531}
2532
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002533static size_t trace__fprintf_threads_header(FILE *fp)
2534{
2535 size_t printed;
2536
Pekka Enberg99ff7152013-11-12 16:42:14 +02002537 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002538
2539 return printed;
2540}
2541
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002542DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2543 struct stats *stats;
2544 double msecs;
2545 int syscall;
2546)
2547{
2548 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2549 struct stats *stats = source->priv;
2550
2551 entry->syscall = source->i;
2552 entry->stats = stats;
2553 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2554}
2555
David Ahernbf2575c2013-10-08 21:26:53 -06002556static size_t thread__dump_stats(struct thread_trace *ttrace,
2557 struct trace *trace, FILE *fp)
2558{
David Ahernbf2575c2013-10-08 21:26:53 -06002559 size_t printed = 0;
2560 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002561 struct rb_node *nd;
2562 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002563
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002564 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002565 return 0;
2566
2567 printed += fprintf(fp, "\n");
2568
Milian Wolff834fd462015-08-06 11:24:29 +02002569 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2570 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2571 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002572
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002573 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002574 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002575 if (stats) {
2576 double min = (double)(stats->min) / NSEC_PER_MSEC;
2577 double max = (double)(stats->max) / NSEC_PER_MSEC;
2578 double avg = avg_stats(stats);
2579 double pct;
2580 u64 n = (u64) stats->n;
2581
2582 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2583 avg /= NSEC_PER_MSEC;
2584
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002585 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002586 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002587 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002588 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002589 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002590 }
David Ahernbf2575c2013-10-08 21:26:53 -06002591 }
2592
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002593 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002594 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002595
2596 return printed;
2597}
2598
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002599static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002600{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002601 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002602 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002603 double ratio;
2604
2605 if (ttrace == NULL)
2606 return 0;
2607
2608 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2609
Pekka Enberg15e65c62013-11-14 18:43:30 +02002610 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002611 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002612 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002613 if (ttrace->pfmaj)
2614 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2615 if (ttrace->pfmin)
2616 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002617 if (trace->sched)
2618 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2619 else if (fputc('\n', fp) != EOF)
2620 ++printed;
2621
David Ahernbf2575c2013-10-08 21:26:53 -06002622 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002623
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002624 return printed;
2625}
David Ahern896cbb52013-09-28 13:12:59 -06002626
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002627static unsigned long thread__nr_events(struct thread_trace *ttrace)
2628{
2629 return ttrace ? ttrace->nr_events : 0;
2630}
2631
2632DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2633 struct thread *thread;
2634)
2635{
2636 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002637}
2638
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002639static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2640{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002641 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2642 size_t printed = trace__fprintf_threads_header(fp);
2643 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002644
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002645 if (threads == NULL) {
2646 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2647 return 0;
2648 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002649
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002650 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002651 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2652
2653 resort_rb__delete(threads);
2654
2655 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002656}
2657
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002658static int trace__set_duration(const struct option *opt, const char *str,
2659 int unset __maybe_unused)
2660{
2661 struct trace *trace = opt->value;
2662
2663 trace->duration_filter = atof(str);
2664 return 0;
2665}
2666
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002667static int trace__set_filter_pids(const struct option *opt, const char *str,
2668 int unset __maybe_unused)
2669{
2670 int ret = -1;
2671 size_t i;
2672 struct trace *trace = opt->value;
2673 /*
2674 * FIXME: introduce a intarray class, plain parse csv and create a
2675 * { int nr, int entries[] } struct...
2676 */
2677 struct intlist *list = intlist__new(str);
2678
2679 if (list == NULL)
2680 return -1;
2681
2682 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2683 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2684
2685 if (trace->filter_pids.entries == NULL)
2686 goto out;
2687
2688 trace->filter_pids.entries[0] = getpid();
2689
2690 for (i = 1; i < trace->filter_pids.nr; ++i)
2691 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2692
2693 intlist__delete(list);
2694 ret = 0;
2695out:
2696 return ret;
2697}
2698
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002699static int trace__open_output(struct trace *trace, const char *filename)
2700{
2701 struct stat st;
2702
2703 if (!stat(filename, &st) && st.st_size) {
2704 char oldname[PATH_MAX];
2705
2706 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2707 unlink(oldname);
2708 rename(filename, oldname);
2709 }
2710
2711 trace->output = fopen(filename, "w");
2712
2713 return trace->output == NULL ? -errno : 0;
2714}
2715
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002716static int parse_pagefaults(const struct option *opt, const char *str,
2717 int unset __maybe_unused)
2718{
2719 int *trace_pgfaults = opt->value;
2720
2721 if (strcmp(str, "all") == 0)
2722 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2723 else if (strcmp(str, "maj") == 0)
2724 *trace_pgfaults |= TRACE_PFMAJ;
2725 else if (strcmp(str, "min") == 0)
2726 *trace_pgfaults |= TRACE_PFMIN;
2727 else
2728 return -1;
2729
2730 return 0;
2731}
2732
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002733static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2734{
2735 struct perf_evsel *evsel;
2736
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002737 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002738 evsel->handler = handler;
2739}
2740
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002741/*
2742 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2743 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2744 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2745 *
2746 * It'd be better to introduce a parse_options() variant that would return a
2747 * list with the terms it didn't match to an event...
2748 */
2749static int trace__parse_events_option(const struct option *opt, const char *str,
2750 int unset __maybe_unused)
2751{
2752 struct trace *trace = (struct trace *)opt->value;
2753 const char *s = str;
2754 char *sep = NULL, *lists[2] = { NULL, NULL, };
2755 int len = strlen(str), err = -1, list;
2756 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2757 char group_name[PATH_MAX];
2758
2759 if (strace_groups_dir == NULL)
2760 return -1;
2761
2762 if (*s == '!') {
2763 ++s;
2764 trace->not_ev_qualifier = true;
2765 }
2766
2767 while (1) {
2768 if ((sep = strchr(s, ',')) != NULL)
2769 *sep = '\0';
2770
2771 list = 0;
2772 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2773 list = 1;
2774 } else {
2775 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2776 if (access(group_name, R_OK) == 0)
2777 list = 1;
2778 }
2779
2780 if (lists[list]) {
2781 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2782 } else {
2783 lists[list] = malloc(len);
2784 if (lists[list] == NULL)
2785 goto out;
2786 strcpy(lists[list], s);
2787 }
2788
2789 if (!sep)
2790 break;
2791
2792 *sep = ',';
2793 s = sep + 1;
2794 }
2795
2796 if (lists[1] != NULL) {
2797 struct strlist_config slist_config = {
2798 .dirname = strace_groups_dir,
2799 };
2800
2801 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2802 if (trace->ev_qualifier == NULL) {
2803 fputs("Not enough memory to parse event qualifier", trace->output);
2804 goto out;
2805 }
2806
2807 if (trace__validate_ev_qualifier(trace))
2808 goto out;
2809 }
2810
2811 err = 0;
2812
2813 if (lists[0]) {
2814 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2815 "event selector. use 'perf list' to list available events",
2816 parse_events_option);
2817 err = parse_events_option(&o, lists[0], 0);
2818 }
2819out:
2820 if (sep)
2821 *sep = ',';
2822
2823 return err;
2824}
2825
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002826int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002827{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002828 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002829 "perf trace [<options>] [<command>]",
2830 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002831 "perf trace record [<options>] [<command>]",
2832 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002833 NULL
2834 };
2835 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002836 .syscalls = {
2837 . max = -1,
2838 },
2839 .opts = {
2840 .target = {
2841 .uid = UINT_MAX,
2842 .uses_mmap = true,
2843 },
2844 .user_freq = UINT_MAX,
2845 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002846 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002847 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002848 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002849 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002850 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002851 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002852 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002853 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002854 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002855 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002856 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002857 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002858 OPT_CALLBACK('e', "event", &trace, "event",
2859 "event/syscall selector. use 'perf list' to list available events",
2860 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002861 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2862 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002863 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002864 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2865 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002866 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002867 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002868 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2869 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002870 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002871 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002872 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2873 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002874 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002875 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002876 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002877 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002878 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002879 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002880 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2881 "number of mmap data pages",
2882 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002883 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002884 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002885 OPT_CALLBACK(0, "duration", &trace, "float",
2886 "show only events with duration > N.M ms",
2887 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002888 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002889 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002890 OPT_BOOLEAN('T', "time", &trace.full_time,
2891 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002892 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2893 "Show only syscall summary with statistics"),
2894 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2895 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002896 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2897 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002898 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002899 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002900 OPT_CALLBACK(0, "call-graph", &trace.opts,
2901 "record_mode[,record_size]", record_callchain_help,
2902 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002903 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2904 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002905 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2906 "Set the minimum stack depth when parsing the callchain, "
2907 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002908 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2909 "Set the maximum stack depth when parsing the callchain, "
2910 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002911 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002912 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2913 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002914 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2915 "ms to wait before starting measurement after program "
2916 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002917 OPT_END()
2918 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002919 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002920 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002921 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002922 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002923 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002924
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002925 signal(SIGSEGV, sighandler_dump_stack);
2926 signal(SIGFPE, sighandler_dump_stack);
2927
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002928 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002929 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002930
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002931 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002932 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002933 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002934 goto out;
2935 }
2936
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002937 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2938 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002939
Wang Nand7888572016-04-08 15:07:24 +00002940 err = bpf__setup_stdout(trace.evlist);
2941 if (err) {
2942 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2943 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2944 goto out;
2945 }
2946
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002947 err = -1;
2948
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002949 if (trace.trace_pgfaults) {
2950 trace.opts.sample_address = true;
2951 trace.opts.sample_time = true;
2952 }
2953
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002954 if (trace.opts.mmap_pages == UINT_MAX)
2955 mmap_pages_user_set = false;
2956
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002957 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002958 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002959 max_stack_user_set = false;
2960 }
2961
2962#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002963 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002964 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2965#endif
2966
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002967 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002968 if (!mmap_pages_user_set && geteuid() == 0)
2969 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2970
Milian Wolff566a0882016-04-08 13:34:15 +02002971 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002972 }
Milian Wolff566a0882016-04-08 13:34:15 +02002973
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002974 if (trace.evlist->nr_entries > 0)
2975 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2976
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002977 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2978 return trace__record(&trace, argc-1, &argv[1]);
2979
2980 /* summary_only implies summary option, but don't overwrite summary if set */
2981 if (trace.summary_only)
2982 trace.summary = trace.summary_only;
2983
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002984 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2985 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002986 pr_err("Please specify something to trace.\n");
2987 return -1;
2988 }
2989
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002990 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002991 pr_err("The -e option can't be used with --no-syscalls.\n");
2992 goto out;
2993 }
2994
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002995 if (output_name != NULL) {
2996 err = trace__open_output(&trace, output_name);
2997 if (err < 0) {
2998 perror("failed to create output file");
2999 goto out;
3000 }
3001 }
3002
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003003 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3004
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003005 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003006 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;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003010 }
3011
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003012 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003013 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003014 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003015 fprintf(trace.output, "%s", bf);
3016 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003017 }
3018
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003019 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003020 trace.opts.target.system_wide = true;
3021
David Ahern6810fc92013-08-28 22:29:52 -06003022 if (input_name)
3023 err = trace__replay(&trace);
3024 else
3025 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003026
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003027out_close:
3028 if (output_name != NULL)
3029 fclose(trace.output);
3030out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003031 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003032}