blob: d1c8cdc6788b4003ca40129eaf6c339240d2643a [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030024#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060025#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030026#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030027#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060028#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030029#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060030#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030031#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060032#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030033#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060034#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030035#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010036#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070037#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000038#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020039#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030040#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030041#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030042#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030043#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030044
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030045#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030046#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030047#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030048#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030049#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020050#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030051#include <linux/filter.h>
52#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030053#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030054#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030055#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030056#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030057
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030058#include "sane_ctype.h"
59
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030060#ifndef O_CLOEXEC
61# define O_CLOEXEC 02000000
62#endif
63
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030064struct trace {
65 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030066 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030067 struct {
68 int max;
69 struct syscall *table;
70 struct {
71 struct perf_evsel *sys_enter,
72 *sys_exit;
73 } events;
74 } syscalls;
75 struct record_opts opts;
76 struct perf_evlist *evlist;
77 struct machine *host;
78 struct thread *current;
79 u64 base_time;
80 FILE *output;
81 unsigned long nr_events;
82 struct strlist *ev_qualifier;
83 struct {
84 size_t nr;
85 int *entries;
86 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030087 struct {
88 size_t nr;
89 pid_t *entries;
90 } filter_pids;
91 double duration_filter;
92 double runtime_ms;
93 struct {
94 u64 vfs_getname,
95 proc_getname;
96 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030097 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -030098 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030099 bool not_ev_qualifier;
100 bool live;
101 bool full_time;
102 bool sched;
103 bool multiple_threads;
104 bool summary;
105 bool summary_only;
106 bool show_comm;
107 bool show_tool_stats;
108 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300109 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300110 bool force;
111 bool vfs_getname;
112 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300113 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300114};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300115
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300116struct tp_field {
117 int offset;
118 union {
119 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
120 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
121 };
122};
123
124#define TP_UINT_FIELD(bits) \
125static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
126{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500127 u##bits value; \
128 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
129 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300130}
131
132TP_UINT_FIELD(8);
133TP_UINT_FIELD(16);
134TP_UINT_FIELD(32);
135TP_UINT_FIELD(64);
136
137#define TP_UINT_FIELD__SWAPPED(bits) \
138static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
139{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500140 u##bits value; \
141 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300142 return bswap_##bits(value);\
143}
144
145TP_UINT_FIELD__SWAPPED(16);
146TP_UINT_FIELD__SWAPPED(32);
147TP_UINT_FIELD__SWAPPED(64);
148
149static int tp_field__init_uint(struct tp_field *field,
150 struct format_field *format_field,
151 bool needs_swap)
152{
153 field->offset = format_field->offset;
154
155 switch (format_field->size) {
156 case 1:
157 field->integer = tp_field__u8;
158 break;
159 case 2:
160 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
161 break;
162 case 4:
163 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
164 break;
165 case 8:
166 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
167 break;
168 default:
169 return -1;
170 }
171
172 return 0;
173}
174
175static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
176{
177 return sample->raw_data + field->offset;
178}
179
180static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
181{
182 field->offset = format_field->offset;
183 field->pointer = tp_field__ptr;
184 return 0;
185}
186
187struct syscall_tp {
188 struct tp_field id;
189 union {
190 struct tp_field args, ret;
191 };
192};
193
194static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
195 struct tp_field *field,
196 const char *name)
197{
198 struct format_field *format_field = perf_evsel__field(evsel, name);
199
200 if (format_field == NULL)
201 return -1;
202
203 return tp_field__init_uint(field, format_field, evsel->needs_swap);
204}
205
206#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
207 ({ struct syscall_tp *sc = evsel->priv;\
208 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
209
210static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
211 struct tp_field *field,
212 const char *name)
213{
214 struct format_field *format_field = perf_evsel__field(evsel, name);
215
216 if (format_field == NULL)
217 return -1;
218
219 return tp_field__init_ptr(field, format_field);
220}
221
222#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
223 ({ struct syscall_tp *sc = evsel->priv;\
224 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
225
226static void perf_evsel__delete_priv(struct perf_evsel *evsel)
227{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300228 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300229 perf_evsel__delete(evsel);
230}
231
Namhyung Kim96695d42013-11-12 08:51:45 -0300232static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
233{
234 evsel->priv = malloc(sizeof(struct syscall_tp));
235 if (evsel->priv != NULL) {
236 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
237 goto out_delete;
238
239 evsel->handler = handler;
240 return 0;
241 }
242
243 return -ENOMEM;
244
245out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300246 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300247 return -ENOENT;
248}
249
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300250static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300251{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300252 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300253
David Ahern9aca7f12013-12-04 19:41:39 -0700254 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200255 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700256 evsel = perf_evsel__newtp("syscalls", direction);
257
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200258 if (IS_ERR(evsel))
259 return NULL;
260
261 if (perf_evsel__init_syscall_tp(evsel, handler))
262 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300263
264 return evsel;
265
266out_delete:
267 perf_evsel__delete_priv(evsel);
268 return NULL;
269}
270
271#define perf_evsel__sc_tp_uint(evsel, name, sample) \
272 ({ struct syscall_tp *fields = evsel->priv; \
273 fields->name.integer(&fields->name, sample); })
274
275#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
276 ({ struct syscall_tp *fields = evsel->priv; \
277 fields->name.pointer(&fields->name, sample); })
278
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300279struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300280 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300281 int nr_entries;
282 const char **entries;
283};
284
285#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
286 .nr_entries = ARRAY_SIZE(array), \
287 .entries = array, \
288}
289
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300290#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
291 .offset = off, \
292 .nr_entries = ARRAY_SIZE(array), \
293 .entries = array, \
294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300301 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302
303 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300304 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305
306 return scnprintf(bf, size, "%s", sa->entries[idx]);
307}
308
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300309static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
310 struct syscall_arg *arg)
311{
312 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
313}
314
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300315#define SCA_STRARRAY syscall_arg__scnprintf_strarray
316
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300317#if defined(__i386__) || defined(__x86_64__)
318/*
319 * FIXME: Make this available to all arches as soon as the ioctl beautifier
320 * gets rewritten to support all arches.
321 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300322static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
323 struct syscall_arg *arg)
324{
325 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
326}
327
328#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300329#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300330
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300331static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
332 struct syscall_arg *arg);
333
334#define SCA_FD syscall_arg__scnprintf_fd
335
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300336#ifndef AT_FDCWD
337#define AT_FDCWD -100
338#endif
339
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300340static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
341 struct syscall_arg *arg)
342{
343 int fd = arg->val;
344
345 if (fd == AT_FDCWD)
346 return scnprintf(bf, size, "CWD");
347
348 return syscall_arg__scnprintf_fd(bf, size, arg);
349}
350
351#define SCA_FDAT syscall_arg__scnprintf_fd_at
352
353static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
354 struct syscall_arg *arg);
355
356#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
357
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300358static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300359 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300360{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300361 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300362}
363
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300364#define SCA_HEX syscall_arg__scnprintf_hex
365
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300366static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
367 struct syscall_arg *arg)
368{
369 return scnprintf(bf, size, "%d", arg->val);
370}
371
372#define SCA_INT syscall_arg__scnprintf_int
373
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300374static const char *bpf_cmd[] = {
375 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
376 "MAP_GET_NEXT_KEY", "PROG_LOAD",
377};
378static DEFINE_STRARRAY(bpf_cmd);
379
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300380static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
381static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300382
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300383static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
384static DEFINE_STRARRAY(itimers);
385
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300386static const char *keyctl_options[] = {
387 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
388 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
389 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
390 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
391 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
392};
393static DEFINE_STRARRAY(keyctl_options);
394
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300395static const char *whences[] = { "SET", "CUR", "END",
396#ifdef SEEK_DATA
397"DATA",
398#endif
399#ifdef SEEK_HOLE
400"HOLE",
401#endif
402};
403static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300404
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300405static const char *fcntl_cmds[] = {
406 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
407 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
408 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
409 "F_GETOWNER_UIDS",
410};
411static DEFINE_STRARRAY(fcntl_cmds);
412
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300413static const char *rlimit_resources[] = {
414 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
415 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
416 "RTTIME",
417};
418static DEFINE_STRARRAY(rlimit_resources);
419
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300420static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
421static DEFINE_STRARRAY(sighow);
422
David Ahern4f8c1b72013-09-22 19:45:00 -0600423static const char *clockid[] = {
424 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300425 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
426 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600427};
428static DEFINE_STRARRAY(clockid);
429
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300430static const char *socket_families[] = {
431 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
432 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
433 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
434 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
435 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
436 "ALG", "NFC", "VSOCK",
437};
438static DEFINE_STRARRAY(socket_families);
439
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300440static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
441 struct syscall_arg *arg)
442{
443 size_t printed = 0;
444 int mode = arg->val;
445
446 if (mode == F_OK) /* 0 */
447 return scnprintf(bf, size, "F");
448#define P_MODE(n) \
449 if (mode & n##_OK) { \
450 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
451 mode &= ~n##_OK; \
452 }
453
454 P_MODE(R);
455 P_MODE(W);
456 P_MODE(X);
457#undef P_MODE
458
459 if (mode)
460 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
461
462 return printed;
463}
464
465#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
466
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300467static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
468 struct syscall_arg *arg);
469
470#define SCA_FILENAME syscall_arg__scnprintf_filename
471
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300472static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
473 struct syscall_arg *arg)
474{
475 int printed = 0, flags = arg->val;
476
477#define P_FLAG(n) \
478 if (flags & O_##n) { \
479 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
480 flags &= ~O_##n; \
481 }
482
483 P_FLAG(CLOEXEC);
484 P_FLAG(NONBLOCK);
485#undef P_FLAG
486
487 if (flags)
488 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
489
490 return printed;
491}
492
493#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
494
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300495#if defined(__i386__) || defined(__x86_64__)
496/*
497 * FIXME: Make this available to all arches.
498 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300499#define TCGETS 0x5401
500
501static const char *tioctls[] = {
502 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
503 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
504 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
505 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
506 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
507 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
508 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
509 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
510 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
511 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
512 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
513 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
514 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
515 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
516 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
517};
518
519static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300520#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300521
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300522#ifndef GRND_NONBLOCK
523#define GRND_NONBLOCK 0x0001
524#endif
525#ifndef GRND_RANDOM
526#define GRND_RANDOM 0x0002
527#endif
528
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300529static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
530 struct syscall_arg *arg)
531{
532 int printed = 0, flags = arg->val;
533
534#define P_FLAG(n) \
535 if (flags & GRND_##n) { \
536 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
537 flags &= ~GRND_##n; \
538 }
539
540 P_FLAG(RANDOM);
541 P_FLAG(NONBLOCK);
542#undef P_FLAG
543
544 if (flags)
545 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
546
547 return printed;
548}
549
550#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
551
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300552#define STRARRAY(arg, name, array) \
553 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
554 .arg_parm = { [arg] = &strarray__##array, }
555
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300556#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300557#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300558#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300559#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300560#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300561#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300562#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300563#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300564#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300565#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300566#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300567#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300568#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300569#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300570
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300571static struct syscall_fmt {
572 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300573 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300574 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300575 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300576 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300577 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300578 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300579 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300580} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300581 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300582 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300583 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300584 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300585 { .name = "brk", .hexret = true,
586 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300587 { .name = "chdir", .errmsg = true, },
588 { .name = "chmod", .errmsg = true, },
589 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600590 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300591 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300592 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300593 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300594 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300595 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300596 { .name = "dup", .errmsg = true, },
597 { .name = "dup2", .errmsg = true, },
598 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300599 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300600 { .name = "eventfd2", .errmsg = true,
601 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300602 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300603 { .name = "fadvise64", .errmsg = true, },
604 { .name = "fallocate", .errmsg = true, },
605 { .name = "fchdir", .errmsg = true, },
606 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300607 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300608 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300609 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300610 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300611 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300612 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300613 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300614 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300615 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300616 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300617 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
618 { .name = "fsetxattr", .errmsg = true, },
619 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300620 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300621 { .name = "fstatfs", .errmsg = true, },
622 { .name = "fsync", .errmsg = true, },
623 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300624 { .name = "futex", .errmsg = true,
625 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300626 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300627 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300628 { .name = "getdents", .errmsg = true, },
629 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300630 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300631 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300632 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300633 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300634 { .name = "getrandom", .errmsg = true,
635 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300636 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300637 { .name = "getxattr", .errmsg = true, },
638 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300639 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300640 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300641#if defined(__i386__) || defined(__x86_64__)
642/*
643 * FIXME: Make this available to all arches.
644 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300645 [1] = SCA_STRHEXARRAY, /* cmd */
646 [2] = SCA_HEX, /* arg */ },
647 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300648#else
649 [2] = SCA_HEX, /* arg */ }, },
650#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300651 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300652 { .name = "kill", .errmsg = true,
653 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300654 { .name = "lchown", .errmsg = true, },
655 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300656 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300657 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300658 { .name = "listxattr", .errmsg = true, },
659 { .name = "llistxattr", .errmsg = true, },
660 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300661 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300662 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300663 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300664 { .name = "lsetxattr", .errmsg = true, },
665 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
666 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300667 { .name = "madvise", .errmsg = true,
668 .arg_scnprintf = { [0] = SCA_HEX, /* start */
669 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300670 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300671 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300672 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
673 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300674 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300675 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300676 { .name = "mlock", .errmsg = true,
677 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
678 { .name = "mlockall", .errmsg = true,
679 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300680 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300681 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300682 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300683 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300684 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300685 .arg_scnprintf = { [0] = SCA_HEX, /* start */
686 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300687 { .name = "mq_unlink", .errmsg = true,
688 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300689 { .name = "mremap", .hexret = true,
690 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300691 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300692 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300693 { .name = "munlock", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300695 { .name = "munmap", .errmsg = true,
696 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300697 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300698 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300699 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300700 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300701 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300702 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300703 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300704 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
705 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300706 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300707 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
708 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300709 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300710 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300711 [3] = SCA_FD, /* group_fd */
712 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300713 { .name = "pipe2", .errmsg = true,
714 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300715 { .name = "poll", .errmsg = true, .timeout = true, },
716 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300717 { .name = "pread", .errmsg = true, .alias = "pread64", },
718 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300719 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300720 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
721 { .name = "pwritev", .errmsg = true, },
722 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300723 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300724 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300725 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300726 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300727 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300728 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300729 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300730 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300731 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300732 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300733 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300734 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300735 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300736 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300737 { .name = "rt_sigaction", .errmsg = true,
738 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300739 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300740 { .name = "rt_sigqueueinfo", .errmsg = true,
741 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
742 { .name = "rt_tgsigqueueinfo", .errmsg = true,
743 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300744 { .name = "sched_getattr", .errmsg = true, },
745 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300746 { .name = "sched_setscheduler", .errmsg = true,
747 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300748 { .name = "seccomp", .errmsg = true,
749 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
750 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300751 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300752 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300753 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300754 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300755 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300756 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300757 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300758 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300759 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300760 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300761 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300762 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300763 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300764 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300765 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
766 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300767 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300768 { .name = "socketpair", .errmsg = true,
769 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
770 [1] = SCA_SK_TYPE, /* type */ },
771 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300772 { .name = "stat", .errmsg = true, .alias = "newstat", },
773 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300774 { .name = "statx", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
776 [2] = SCA_STATX_FLAGS, /* flags */
777 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300778 { .name = "swapoff", .errmsg = true,
779 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
780 { .name = "swapon", .errmsg = true,
781 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300782 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300783 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300784 { .name = "tgkill", .errmsg = true,
785 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
786 { .name = "tkill", .errmsg = true,
787 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300788 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300789 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300790 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300791 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
792 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300793 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300794 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
795 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300796 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300797 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300798 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300799 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300800 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300801 { .name = "write", .errmsg = true, },
802 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300803};
804
805static int syscall_fmt__cmp(const void *name, const void *fmtp)
806{
807 const struct syscall_fmt *fmt = fmtp;
808 return strcmp(name, fmt->name);
809}
810
811static struct syscall_fmt *syscall_fmt__find(const char *name)
812{
813 const int nmemb = ARRAY_SIZE(syscall_fmts);
814 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
815}
816
817struct syscall {
818 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300819 int nr_args;
820 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300821 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300822 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300823 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300824 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300825 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300826};
827
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300828/*
829 * We need to have this 'calculated' boolean because in some cases we really
830 * don't know what is the duration of a syscall, for instance, when we start
831 * a session and some threads are waiting for a syscall to finish, say 'poll',
832 * in which case all we can do is to print "( ? ) for duration and for the
833 * start timestamp.
834 */
835static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200836{
837 double duration = (double)t / NSEC_PER_MSEC;
838 size_t printed = fprintf(fp, "(");
839
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300840 if (!calculated)
841 printed += fprintf(fp, " ? ");
842 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200843 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
844 else if (duration >= 0.01)
845 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
846 else
847 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300848 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200849}
850
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300851/**
852 * filename.ptr: The filename char pointer that will be vfs_getname'd
853 * filename.entry_str_pos: Where to insert the string translated from
854 * filename.ptr by the vfs_getname tracepoint/kprobe.
855 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300856struct thread_trace {
857 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300858 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300859 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400860 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300861 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300862 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300863 struct {
864 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300865 short int entry_str_pos;
866 bool pending_open;
867 unsigned int namelen;
868 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300869 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300870 struct {
871 int max;
872 char **table;
873 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600874
875 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876};
877
878static struct thread_trace *thread_trace__new(void)
879{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300880 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
881
882 if (ttrace)
883 ttrace->paths.max = -1;
884
David Ahernbf2575c2013-10-08 21:26:53 -0600885 ttrace->syscall_stats = intlist__new(NULL);
886
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300887 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300888}
889
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300890static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300891{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300892 struct thread_trace *ttrace;
893
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300894 if (thread == NULL)
895 goto fail;
896
Namhyung Kim89dceb22014-10-06 09:46:03 +0900897 if (thread__priv(thread) == NULL)
898 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300899
Namhyung Kim89dceb22014-10-06 09:46:03 +0900900 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300901 goto fail;
902
Namhyung Kim89dceb22014-10-06 09:46:03 +0900903 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300904 ++ttrace->nr_events;
905
906 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300907fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300908 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909 "WARNING: not enough memory, dropping samples!\n");
910 return NULL;
911}
912
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400913#define TRACE_PFMAJ (1 << 0)
914#define TRACE_PFMIN (1 << 1)
915
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300916static const size_t trace__entry_str_size = 2048;
917
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300918static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300919{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900920 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300921
922 if (fd > ttrace->paths.max) {
923 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
924
925 if (npath == NULL)
926 return -1;
927
928 if (ttrace->paths.max != -1) {
929 memset(npath + ttrace->paths.max + 1, 0,
930 (fd - ttrace->paths.max) * sizeof(char *));
931 } else {
932 memset(npath, 0, (fd + 1) * sizeof(char *));
933 }
934
935 ttrace->paths.table = npath;
936 ttrace->paths.max = fd;
937 }
938
939 ttrace->paths.table[fd] = strdup(pathname);
940
941 return ttrace->paths.table[fd] != NULL ? 0 : -1;
942}
943
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300944static int thread__read_fd_path(struct thread *thread, int fd)
945{
946 char linkname[PATH_MAX], pathname[PATH_MAX];
947 struct stat st;
948 int ret;
949
950 if (thread->pid_ == thread->tid) {
951 scnprintf(linkname, sizeof(linkname),
952 "/proc/%d/fd/%d", thread->pid_, fd);
953 } else {
954 scnprintf(linkname, sizeof(linkname),
955 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
956 }
957
958 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
959 return -1;
960
961 ret = readlink(linkname, pathname, sizeof(pathname));
962
963 if (ret < 0 || ret > st.st_size)
964 return -1;
965
966 pathname[ret] = '\0';
967 return trace__set_fd_pathname(thread, fd, pathname);
968}
969
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300970static const char *thread__fd_path(struct thread *thread, int fd,
971 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300972{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900973 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300974
975 if (ttrace == NULL)
976 return NULL;
977
978 if (fd < 0)
979 return NULL;
980
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300981 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300982 if (!trace->live)
983 return NULL;
984 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300985 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300986 return NULL;
987 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300988
989 return ttrace->paths.table[fd];
990}
991
992static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
993 struct syscall_arg *arg)
994{
995 int fd = arg->val;
996 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300997 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300998
999 if (path)
1000 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1001
1002 return printed;
1003}
1004
1005static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1006 struct syscall_arg *arg)
1007{
1008 int fd = arg->val;
1009 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001010 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001011
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001012 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1013 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001014
1015 return printed;
1016}
1017
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001018static void thread__set_filename_pos(struct thread *thread, const char *bf,
1019 unsigned long ptr)
1020{
1021 struct thread_trace *ttrace = thread__priv(thread);
1022
1023 ttrace->filename.ptr = ptr;
1024 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1025}
1026
1027static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1028 struct syscall_arg *arg)
1029{
1030 unsigned long ptr = arg->val;
1031
1032 if (!arg->trace->vfs_getname)
1033 return scnprintf(bf, size, "%#x", ptr);
1034
1035 thread__set_filename_pos(arg->thread, bf, ptr);
1036 return 0;
1037}
1038
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001039static bool trace__filter_duration(struct trace *trace, double t)
1040{
1041 return t < (trace->duration_filter * NSEC_PER_MSEC);
1042}
1043
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001044static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001045{
1046 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1047
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001048 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001049}
1050
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001051/*
1052 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1053 * using ttrace->entry_time for a thread that receives a sys_exit without
1054 * first having received a sys_enter ("poll" issued before tracing session
1055 * starts, lost sys_enter exit due to ring buffer overflow).
1056 */
1057static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1058{
1059 if (tstamp > 0)
1060 return __trace__fprintf_tstamp(trace, tstamp, fp);
1061
1062 return fprintf(fp, " ? ");
1063}
1064
Namhyung Kimf15eb532012-10-05 14:02:16 +09001065static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001066static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001067
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001068static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001069{
1070 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001071 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001072}
1073
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001074static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001075 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001076{
1077 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001078 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001079
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001080 if (trace->multiple_threads) {
1081 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001082 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001083 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001084 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001085
1086 return printed;
1087}
1088
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001089static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001090 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001091{
1092 int ret = 0;
1093
1094 switch (event->header.type) {
1095 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001096 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001097 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001098 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001099 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001101 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001102 break;
1103 }
1104
1105 return ret;
1106}
1107
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001108static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001110 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111 struct machine *machine)
1112{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001113 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001114 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001115}
1116
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001117static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1118{
1119 struct machine *machine = vmachine;
1120
1121 if (machine->kptr_restrict_warned)
1122 return NULL;
1123
1124 if (symbol_conf.kptr_restrict) {
1125 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1126 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1127 "Kernel samples will not be resolved.\n");
1128 machine->kptr_restrict_warned = true;
1129 return NULL;
1130 }
1131
1132 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1133}
1134
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001135static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1136{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001137 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001138
1139 if (err)
1140 return err;
1141
David Ahern8fb598e2013-09-28 13:13:00 -06001142 trace->host = machine__new_host();
1143 if (trace->host == NULL)
1144 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001146 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001147 return -errno;
1148
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001149 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001150 evlist->threads, trace__tool_process, false,
1151 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001152 if (err)
1153 symbol__exit();
1154
1155 return err;
1156}
1157
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001158static int syscall__set_arg_fmts(struct syscall *sc)
1159{
1160 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001161 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001162
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001163 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001164 if (sc->arg_scnprintf == NULL)
1165 return -1;
1166
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001167 if (sc->fmt)
1168 sc->arg_parm = sc->fmt->arg_parm;
1169
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001170 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001171 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1172 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001173 else if (strcmp(field->type, "const char *") == 0 &&
1174 (strcmp(field->name, "filename") == 0 ||
1175 strcmp(field->name, "path") == 0 ||
1176 strcmp(field->name, "pathname") == 0))
1177 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001178 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001179 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001180 else if (strcmp(field->type, "pid_t") == 0)
1181 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001182 else if (strcmp(field->type, "umode_t") == 0)
1183 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001184 else if ((strcmp(field->type, "int") == 0 ||
1185 strcmp(field->type, "unsigned int") == 0 ||
1186 strcmp(field->type, "long") == 0) &&
1187 (len = strlen(field->name)) >= 2 &&
1188 strcmp(field->name + len - 2, "fd") == 0) {
1189 /*
1190 * /sys/kernel/tracing/events/syscalls/sys_enter*
1191 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1192 * 65 int
1193 * 23 unsigned int
1194 * 7 unsigned long
1195 */
1196 sc->arg_scnprintf[idx] = SCA_FD;
1197 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001198 ++idx;
1199 }
1200
1201 return 0;
1202}
1203
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001204static int trace__read_syscall_info(struct trace *trace, int id)
1205{
1206 char tp_name[128];
1207 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001208 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001209
1210 if (name == NULL)
1211 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001212
1213 if (id > trace->syscalls.max) {
1214 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1215
1216 if (nsyscalls == NULL)
1217 return -1;
1218
1219 if (trace->syscalls.max != -1) {
1220 memset(nsyscalls + trace->syscalls.max + 1, 0,
1221 (id - trace->syscalls.max) * sizeof(*sc));
1222 } else {
1223 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1224 }
1225
1226 trace->syscalls.table = nsyscalls;
1227 trace->syscalls.max = id;
1228 }
1229
1230 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001231 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001232
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001233 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001234
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001235 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001236 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001237
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001238 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001239 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001240 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001241 }
1242
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001243 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001244 return -1;
1245
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001246 sc->args = sc->tp_format->format.fields;
1247 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001248 /*
1249 * We need to check and discard the first variable '__syscall_nr'
1250 * or 'nr' that mean the syscall number. It is needless here.
1251 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1252 */
1253 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001254 sc->args = sc->args->next;
1255 --sc->nr_args;
1256 }
1257
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001258 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1259
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001260 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001261}
1262
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001263static int trace__validate_ev_qualifier(struct trace *trace)
1264{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001265 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001266 struct str_node *pos;
1267
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001268 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1269 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1270 sizeof(trace->ev_qualifier_ids.entries[0]));
1271
1272 if (trace->ev_qualifier_ids.entries == NULL) {
1273 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1274 trace->output);
1275 err = -EINVAL;
1276 goto out;
1277 }
1278
1279 i = 0;
1280
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001281 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001282 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001283 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001284
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001285 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001286 if (err == 0) {
1287 fputs("Error:\tInvalid syscall ", trace->output);
1288 err = -EINVAL;
1289 } else {
1290 fputs(", ", trace->output);
1291 }
1292
1293 fputs(sc, trace->output);
1294 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001295
1296 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001297 }
1298
1299 if (err < 0) {
1300 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1301 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001302 zfree(&trace->ev_qualifier_ids.entries);
1303 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001304 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001305out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001306 return err;
1307}
1308
David Ahern55d43bca2015-02-19 15:00:22 -05001309/*
1310 * args is to be interpreted as a series of longs but we need to handle
1311 * 8-byte unaligned accesses. args points to raw_data within the event
1312 * and raw_data is guaranteed to be 8-byte unaligned because it is
1313 * preceded by raw_size which is a u32. So we need to copy args to a temp
1314 * variable to read it. Most notably this avoids extended load instructions
1315 * on unaligned addresses
1316 */
1317
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001318static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001319 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001320 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001322 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001323 unsigned char *p;
1324 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001325
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001326 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001327 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001328 u8 bit = 1;
1329 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001330 .idx = 0,
1331 .mask = 0,
1332 .trace = trace,
1333 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001334 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001335
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001336 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001337 field = field->next, ++arg.idx, bit <<= 1) {
1338 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001339 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001340
1341 /* special care for unaligned accesses */
1342 p = args + sizeof(unsigned long) * arg.idx;
1343 memcpy(&val, p, sizeof(val));
1344
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001345 /*
1346 * Suppress this argument if its value is zero and
1347 * and we don't have a string associated in an
1348 * strarray for it.
1349 */
David Ahern55d43bca2015-02-19 15:00:22 -05001350 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001351 !(sc->arg_scnprintf &&
1352 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1353 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001354 continue;
1355
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001356 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001357 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001358 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001359 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001360 if (sc->arg_parm)
1361 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001362 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1363 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001364 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001365 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001366 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001367 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001368 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001369 } else if (IS_ERR(sc->tp_format)) {
1370 /*
1371 * If we managed to read the tracepoint /format file, then we
1372 * may end up not having any args, like with gettid(), so only
1373 * print the raw args when we didn't manage to read it.
1374 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001375 int i = 0;
1376
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001377 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001378 /* special care for unaligned accesses */
1379 p = args + sizeof(unsigned long) * i;
1380 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001381 printed += scnprintf(bf + printed, size - printed,
1382 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001383 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001384 ++i;
1385 }
1386 }
1387
1388 return printed;
1389}
1390
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001391typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001392 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001393 struct perf_sample *sample);
1394
1395static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001396 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001397{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001398
1399 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001400
1401 /*
1402 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1403 * before that, leaving at a higher verbosity level till that is
1404 * explained. Reproduced with plain ftrace with:
1405 *
1406 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1407 * grep "NR -1 " /t/trace_pipe
1408 *
1409 * After generating some load on the machine.
1410 */
1411 if (verbose > 1) {
1412 static u64 n;
1413 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1414 id, perf_evsel__name(evsel), ++n);
1415 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001416 return NULL;
1417 }
1418
1419 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1420 trace__read_syscall_info(trace, id))
1421 goto out_cant_read;
1422
1423 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1424 goto out_cant_read;
1425
1426 return &trace->syscalls.table[id];
1427
1428out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001429 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001430 fprintf(trace->output, "Problems reading syscall %d", id);
1431 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1432 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1433 fputs(" information\n", trace->output);
1434 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001435 return NULL;
1436}
1437
David Ahernbf2575c2013-10-08 21:26:53 -06001438static void thread__update_stats(struct thread_trace *ttrace,
1439 int id, struct perf_sample *sample)
1440{
1441 struct int_node *inode;
1442 struct stats *stats;
1443 u64 duration = 0;
1444
1445 inode = intlist__findnew(ttrace->syscall_stats, id);
1446 if (inode == NULL)
1447 return;
1448
1449 stats = inode->priv;
1450 if (stats == NULL) {
1451 stats = malloc(sizeof(struct stats));
1452 if (stats == NULL)
1453 return;
1454 init_stats(stats);
1455 inode->priv = stats;
1456 }
1457
1458 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1459 duration = sample->time - ttrace->entry_time;
1460
1461 update_stats(stats, duration);
1462}
1463
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001464static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1465{
1466 struct thread_trace *ttrace;
1467 u64 duration;
1468 size_t printed;
1469
1470 if (trace->current == NULL)
1471 return 0;
1472
1473 ttrace = thread__priv(trace->current);
1474
1475 if (!ttrace->entry_pending)
1476 return 0;
1477
1478 duration = sample->time - ttrace->entry_time;
1479
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001480 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001481 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1482 ttrace->entry_pending = false;
1483
1484 return printed;
1485}
1486
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001487static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001488 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001489 struct perf_sample *sample)
1490{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001491 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001492 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001493 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001494 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001495 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001496 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001497 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001498
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001499 if (sc == NULL)
1500 return -1;
1501
David Ahern8fb598e2013-09-28 13:13:00 -06001502 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001503 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001504 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001505 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001506
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001507 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001508
1509 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001510 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001511 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001512 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001513 }
1514
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001515 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001516 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001517
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001518 ttrace->entry_time = sample->time;
1519 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001520 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001521
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001522 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001523 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001524
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001525 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001526 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001527 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001528 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001529 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001530 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001531 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001532 /* See trace__vfs_getname & trace__sys_exit */
1533 ttrace->filename.pending_open = false;
1534 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001535
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001536 if (trace->current != thread) {
1537 thread__put(trace->current);
1538 trace->current = thread__get(thread);
1539 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001540 err = 0;
1541out_put:
1542 thread__put(thread);
1543 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001544}
1545
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001546static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1547 struct perf_sample *sample,
1548 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001549{
1550 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001551
1552 if (machine__resolve(trace->host, &al, sample) < 0 ||
1553 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1554 return -1;
1555
1556 return 0;
1557}
1558
1559static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1560{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001561 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001562 const unsigned int print_opts = EVSEL__PRINT_SYM |
1563 EVSEL__PRINT_DSO |
1564 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001565
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001566 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001567}
1568
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001569static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001570 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001571 struct perf_sample *sample)
1572{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001573 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001574 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001575 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001576 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001577 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001578 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001579 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001580
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001581 if (sc == NULL)
1582 return -1;
1583
David Ahern8fb598e2013-09-28 13:13:00 -06001584 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001585 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001586 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001587 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001588
David Ahernbf2575c2013-10-08 21:26:53 -06001589 if (trace->summary)
1590 thread__update_stats(ttrace, id, sample);
1591
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001592 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001593
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001594 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001595 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1596 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001597 ++trace->stats.vfs_getname;
1598 }
1599
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001600 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001601 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001602 if (trace__filter_duration(trace, duration))
1603 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001604 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001605 } else if (trace->duration_filter)
1606 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001607
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001608 if (sample->callchain) {
1609 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1610 if (callchain_ret == 0) {
1611 if (callchain_cursor.nr < trace->min_stack)
1612 goto out;
1613 callchain_ret = 1;
1614 }
1615 }
1616
David Ahernfd2eaba2013-11-12 09:31:15 -07001617 if (trace->summary_only)
1618 goto out;
1619
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001620 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001621
1622 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001623 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001624 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001625 fprintf(trace->output, " ... [");
1626 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1627 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001628 }
1629
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001630 if (sc->fmt == NULL) {
1631signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001632 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001633 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001634 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001635 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001636 *e = audit_errno_to_name(-ret);
1637
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001638 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001639 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001640 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001641 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001642 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001643 else if (sc->fmt->errpid) {
1644 struct thread *child = machine__find_thread(trace->host, ret, ret);
1645
1646 if (child != NULL) {
1647 fprintf(trace->output, ") = %ld", ret);
1648 if (child->comm_set)
1649 fprintf(trace->output, " (%s)", thread__comm_str(child));
1650 thread__put(child);
1651 }
1652 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001653 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001654
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001655 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001656
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001657 if (callchain_ret > 0)
1658 trace__fprintf_callchain(trace, sample);
1659 else if (callchain_ret < 0)
1660 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001661out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001662 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001663 err = 0;
1664out_put:
1665 thread__put(thread);
1666 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001667}
1668
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001669static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001670 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001671 struct perf_sample *sample)
1672{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001673 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1674 struct thread_trace *ttrace;
1675 size_t filename_len, entry_str_len, to_move;
1676 ssize_t remaining_space;
1677 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001678 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001679
1680 if (!thread)
1681 goto out;
1682
1683 ttrace = thread__priv(thread);
1684 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001685 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001686
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001687 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001688 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001689 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001690
1691 if (ttrace->filename.namelen < filename_len) {
1692 char *f = realloc(ttrace->filename.name, filename_len + 1);
1693
1694 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001695 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001696
1697 ttrace->filename.namelen = filename_len;
1698 ttrace->filename.name = f;
1699 }
1700
1701 strcpy(ttrace->filename.name, filename);
1702 ttrace->filename.pending_open = true;
1703
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001704 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001705 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001706
1707 entry_str_len = strlen(ttrace->entry_str);
1708 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1709 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001710 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001711
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001712 if (filename_len > (size_t)remaining_space) {
1713 filename += filename_len - remaining_space;
1714 filename_len = remaining_space;
1715 }
1716
1717 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1718 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1719 memmove(pos + filename_len, pos, to_move);
1720 memcpy(pos, filename, filename_len);
1721
1722 ttrace->filename.ptr = 0;
1723 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001724out_put:
1725 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001726out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001727 return 0;
1728}
1729
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001730static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001731 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001732 struct perf_sample *sample)
1733{
1734 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1735 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001736 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001737 sample->pid,
1738 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001739 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001740
1741 if (ttrace == NULL)
1742 goto out_dump;
1743
1744 ttrace->runtime_ms += runtime_ms;
1745 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001746out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001747 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001748 return 0;
1749
1750out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001751 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001752 evsel->name,
1753 perf_evsel__strval(evsel, sample, "comm"),
1754 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1755 runtime,
1756 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001757 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001758}
1759
Wang Nan1d6c9402016-02-26 09:31:55 +00001760static void bpf_output__printer(enum binary_printer_ops op,
1761 unsigned int val, void *extra)
1762{
1763 FILE *output = extra;
1764 unsigned char ch = (unsigned char)val;
1765
1766 switch (op) {
1767 case BINARY_PRINT_CHAR_DATA:
1768 fprintf(output, "%c", isprint(ch) ? ch : '.');
1769 break;
1770 case BINARY_PRINT_DATA_BEGIN:
1771 case BINARY_PRINT_LINE_BEGIN:
1772 case BINARY_PRINT_ADDR:
1773 case BINARY_PRINT_NUM_DATA:
1774 case BINARY_PRINT_NUM_PAD:
1775 case BINARY_PRINT_SEP:
1776 case BINARY_PRINT_CHAR_PAD:
1777 case BINARY_PRINT_LINE_END:
1778 case BINARY_PRINT_DATA_END:
1779 default:
1780 break;
1781 }
1782}
1783
1784static void bpf_output__fprintf(struct trace *trace,
1785 struct perf_sample *sample)
1786{
1787 print_binary(sample->raw_data, sample->raw_size, 8,
1788 bpf_output__printer, trace->output);
1789}
1790
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001791static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1792 union perf_event *event __maybe_unused,
1793 struct perf_sample *sample)
1794{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001795 int callchain_ret = 0;
1796
1797 if (sample->callchain) {
1798 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1799 if (callchain_ret == 0) {
1800 if (callchain_cursor.nr < trace->min_stack)
1801 goto out;
1802 callchain_ret = 1;
1803 }
1804 }
1805
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001806 trace__printf_interrupted_entry(trace, sample);
1807 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001808
1809 if (trace->trace_syscalls)
1810 fprintf(trace->output, "( ): ");
1811
1812 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001813
Wang Nan1d6c9402016-02-26 09:31:55 +00001814 if (perf_evsel__is_bpf_output(evsel)) {
1815 bpf_output__fprintf(trace, sample);
1816 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001817 event_format__fprintf(evsel->tp_format, sample->cpu,
1818 sample->raw_data, sample->raw_size,
1819 trace->output);
1820 }
1821
1822 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001823
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001824 if (callchain_ret > 0)
1825 trace__fprintf_callchain(trace, sample);
1826 else if (callchain_ret < 0)
1827 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1828out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001829 return 0;
1830}
1831
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001832static void print_location(FILE *f, struct perf_sample *sample,
1833 struct addr_location *al,
1834 bool print_dso, bool print_sym)
1835{
1836
Namhyung Kimbb963e12017-02-17 17:17:38 +09001837 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001838 fprintf(f, "%s@", al->map->dso->long_name);
1839
Namhyung Kimbb963e12017-02-17 17:17:38 +09001840 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001841 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001842 al->addr - al->sym->start);
1843 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001844 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001845 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001846 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001847}
1848
1849static int trace__pgfault(struct trace *trace,
1850 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001851 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001852 struct perf_sample *sample)
1853{
1854 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001855 struct addr_location al;
1856 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001857 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001858 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001859 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001860
1861 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001862
1863 if (sample->callchain) {
1864 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1865 if (callchain_ret == 0) {
1866 if (callchain_cursor.nr < trace->min_stack)
1867 goto out_put;
1868 callchain_ret = 1;
1869 }
1870 }
1871
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001872 ttrace = thread__trace(thread, trace->output);
1873 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001874 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001875
1876 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1877 ttrace->pfmaj++;
1878 else
1879 ttrace->pfmin++;
1880
1881 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001882 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001883
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001884 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001885 sample->ip, &al);
1886
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001887 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888
1889 fprintf(trace->output, "%sfault [",
1890 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1891 "maj" : "min");
1892
1893 print_location(trace->output, sample, &al, false, true);
1894
1895 fprintf(trace->output, "] => ");
1896
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001897 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001898 sample->addr, &al);
1899
1900 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001901 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001902 MAP__FUNCTION, sample->addr, &al);
1903
1904 if (al.map)
1905 map_type = 'x';
1906 else
1907 map_type = '?';
1908 }
1909
1910 print_location(trace->output, sample, &al, true, false);
1911
1912 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001913
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001914 if (callchain_ret > 0)
1915 trace__fprintf_callchain(trace, sample);
1916 else if (callchain_ret < 0)
1917 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001918out:
1919 err = 0;
1920out_put:
1921 thread__put(thread);
1922 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001923}
1924
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001925static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001926 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001927 struct perf_sample *sample)
1928{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001929 /*
1930 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1931 * and don't use sample->time unconditionally, we may end up having
1932 * some other event in the future without PERF_SAMPLE_TIME for good
1933 * reason, i.e. we may not be interested in its timestamps, just in
1934 * it taking place, picking some piece of information when it
1935 * appears in our event stream (vfs_getname comes to mind).
1936 */
1937 if (trace->base_time == 0 && !trace->full_time &&
1938 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001939 trace->base_time = sample->time;
1940}
1941
David Ahern6810fc92013-08-28 22:29:52 -06001942static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001943 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001944 struct perf_sample *sample,
1945 struct perf_evsel *evsel,
1946 struct machine *machine __maybe_unused)
1947{
1948 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001949 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001950 int err = 0;
1951
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001952 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001953
David Ahernaa07df62016-11-25 09:29:52 -07001954 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1955 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001956 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06001957
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001958 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001959
David Ahern31605652013-12-04 19:41:41 -07001960 if (handler) {
1961 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001962 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001963 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001964out:
1965 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06001966 return err;
1967}
1968
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001969static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001970{
1971 unsigned int rec_argc, i, j;
1972 const char **rec_argv;
1973 const char * const record_args[] = {
1974 "record",
1975 "-R",
1976 "-m", "1024",
1977 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001978 };
1979
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001980 const char * const sc_args[] = { "-e", };
1981 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1982 const char * const majpf_args[] = { "-e", "major-faults" };
1983 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1984 const char * const minpf_args[] = { "-e", "minor-faults" };
1985 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1986
David Ahern9aca7f12013-12-04 19:41:39 -07001987 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001988 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1989 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001990 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1991
1992 if (rec_argv == NULL)
1993 return -ENOMEM;
1994
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001995 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06001996 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001997 rec_argv[j++] = record_args[i];
1998
Stanislav Fomicheve281a962014-06-26 20:14:28 +04001999 if (trace->trace_syscalls) {
2000 for (i = 0; i < sc_args_nr; i++)
2001 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002002
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002003 /* event string may be different for older kernels - e.g., RHEL6 */
2004 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2005 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2006 else if (is_valid_tracepoint("syscalls:sys_enter"))
2007 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2008 else {
2009 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2010 return -1;
2011 }
David Ahern9aca7f12013-12-04 19:41:39 -07002012 }
David Ahern9aca7f12013-12-04 19:41:39 -07002013
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002014 if (trace->trace_pgfaults & TRACE_PFMAJ)
2015 for (i = 0; i < majpf_args_nr; i++)
2016 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002017
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002018 if (trace->trace_pgfaults & TRACE_PFMIN)
2019 for (i = 0; i < minpf_args_nr; i++)
2020 rec_argv[j++] = minpf_args[i];
2021
2022 for (i = 0; i < (unsigned int)argc; i++)
2023 rec_argv[j++] = argv[i];
2024
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002025 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002026}
2027
David Ahernbf2575c2013-10-08 21:26:53 -06002028static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2029
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002030static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002031{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002032 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002033
2034 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002035 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002036
2037 if (perf_evsel__field(evsel, "pathname") == NULL) {
2038 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002039 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002040 }
2041
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002042 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002043 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002044 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002045}
2046
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002047static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002048{
2049 struct perf_evsel *evsel;
2050 struct perf_event_attr attr = {
2051 .type = PERF_TYPE_SOFTWARE,
2052 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002053 };
2054
2055 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002056 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002057
2058 event_attr_init(&attr);
2059
2060 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002061 if (evsel)
2062 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002063
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002064 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002065}
2066
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002067static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2068{
2069 const u32 type = event->header.type;
2070 struct perf_evsel *evsel;
2071
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002072 if (type != PERF_RECORD_SAMPLE) {
2073 trace__process_event(trace, trace->host, event, sample);
2074 return;
2075 }
2076
2077 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2078 if (evsel == NULL) {
2079 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2080 return;
2081 }
2082
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002083 trace__set_base_time(trace, evsel, sample);
2084
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002085 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2086 sample->raw_data == NULL) {
2087 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2088 perf_evsel__name(evsel), sample->tid,
2089 sample->cpu, sample->raw_size);
2090 } else {
2091 tracepoint_handler handler = evsel->handler;
2092 handler(trace, evsel, event, sample);
2093 }
2094}
2095
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002096static int trace__add_syscall_newtp(struct trace *trace)
2097{
2098 int ret = -1;
2099 struct perf_evlist *evlist = trace->evlist;
2100 struct perf_evsel *sys_enter, *sys_exit;
2101
2102 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2103 if (sys_enter == NULL)
2104 goto out;
2105
2106 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2107 goto out_delete_sys_enter;
2108
2109 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2110 if (sys_exit == NULL)
2111 goto out_delete_sys_enter;
2112
2113 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2114 goto out_delete_sys_exit;
2115
2116 perf_evlist__add(evlist, sys_enter);
2117 perf_evlist__add(evlist, sys_exit);
2118
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002119 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002120 /*
2121 * We're interested only in the user space callchain
2122 * leading to the syscall, allow overriding that for
2123 * debugging reasons using --kernel_syscall_callchains
2124 */
2125 sys_exit->attr.exclude_callchain_kernel = 1;
2126 }
2127
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002128 trace->syscalls.events.sys_enter = sys_enter;
2129 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002130
2131 ret = 0;
2132out:
2133 return ret;
2134
2135out_delete_sys_exit:
2136 perf_evsel__delete_priv(sys_exit);
2137out_delete_sys_enter:
2138 perf_evsel__delete_priv(sys_enter);
2139 goto out;
2140}
2141
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002142static int trace__set_ev_qualifier_filter(struct trace *trace)
2143{
2144 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002145 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002146 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2147 trace->ev_qualifier_ids.nr,
2148 trace->ev_qualifier_ids.entries);
2149
2150 if (filter == NULL)
2151 goto out_enomem;
2152
Mathieu Poirier3541c032016-09-16 08:44:04 -06002153 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2154 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002155 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002156 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002157 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002158
2159 free(filter);
2160out:
2161 return err;
2162out_enomem:
2163 errno = ENOMEM;
2164 goto out;
2165}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002166
Namhyung Kimf15eb532012-10-05 14:02:16 +09002167static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002168{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002169 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002170 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002171 int err = -1, i;
2172 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002173 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002174 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002175
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002176 trace->live = true;
2177
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002178 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002179 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002180
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002181 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002182 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002183
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002184 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2185 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2186 if (pgfault_maj == NULL)
2187 goto out_error_mem;
2188 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002189 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002190
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002191 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2192 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2193 if (pgfault_min == NULL)
2194 goto out_error_mem;
2195 perf_evlist__add(evlist, pgfault_min);
2196 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002197
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002198 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002199 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2200 trace__sched_stat_runtime))
2201 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002202
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002203 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2204 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002205 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002206 goto out_delete_evlist;
2207 }
2208
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002209 err = trace__symbols_init(trace, evlist);
2210 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002211 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002212 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002213 }
2214
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002215 perf_evlist__config(evlist, &trace->opts, NULL);
2216
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002217 if (callchain_param.enabled) {
2218 bool use_identifier = false;
2219
2220 if (trace->syscalls.events.sys_exit) {
2221 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2222 &trace->opts, &callchain_param);
2223 use_identifier = true;
2224 }
2225
2226 if (pgfault_maj) {
2227 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2228 use_identifier = true;
2229 }
2230
2231 if (pgfault_min) {
2232 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2233 use_identifier = true;
2234 }
2235
2236 if (use_identifier) {
2237 /*
2238 * Now we have evsels with different sample_ids, use
2239 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2240 * from a fixed position in each ring buffer record.
2241 *
2242 * As of this the changeset introducing this comment, this
2243 * isn't strictly needed, as the fields that can come before
2244 * PERF_SAMPLE_ID are all used, but we'll probably disable
2245 * some of those for things like copying the payload of
2246 * pointer syscall arguments, and for vfs_getname we don't
2247 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2248 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2249 */
2250 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2251 perf_evlist__reset_sample_bit(evlist, ID);
2252 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002253 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002254
Namhyung Kimf15eb532012-10-05 14:02:16 +09002255 signal(SIGCHLD, sig_handler);
2256 signal(SIGINT, sig_handler);
2257
2258 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002259 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002260 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002261 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002262 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002263 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002264 }
2265 }
2266
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002267 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002268 if (err < 0)
2269 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002270
Wang Nanba504232016-02-26 09:31:54 +00002271 err = bpf__apply_obj_config();
2272 if (err) {
2273 char errbuf[BUFSIZ];
2274
2275 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2276 pr_err("ERROR: Apply config to BPF failed: %s\n",
2277 errbuf);
2278 goto out_error_open;
2279 }
2280
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002281 /*
2282 * Better not use !target__has_task() here because we need to cover the
2283 * case where no threads were specified in the command line, but a
2284 * workload was, and in that case we will fill in the thread_map when
2285 * we fork the workload in perf_evlist__prepare_workload.
2286 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002287 if (trace->filter_pids.nr > 0)
2288 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002289 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002290 err = perf_evlist__set_filter_pid(evlist, getpid());
2291
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002292 if (err < 0)
2293 goto out_error_mem;
2294
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002295 if (trace->ev_qualifier_ids.nr > 0) {
2296 err = trace__set_ev_qualifier_filter(trace);
2297 if (err < 0)
2298 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002299
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002300 pr_debug("event qualifier tracepoint filter: %s\n",
2301 trace->syscalls.events.sys_exit->filter);
2302 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002303
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002304 err = perf_evlist__apply_filters(evlist, &evsel);
2305 if (err < 0)
2306 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002307
Jiri Olsaf8850372013-11-28 17:57:22 +01002308 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002309 if (err < 0)
2310 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002311
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002312 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002313 perf_evlist__enable(evlist);
2314
Namhyung Kimf15eb532012-10-05 14:02:16 +09002315 if (forks)
2316 perf_evlist__start_workload(evlist);
2317
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002318 if (trace->opts.initial_delay) {
2319 usleep(trace->opts.initial_delay * 1000);
2320 perf_evlist__enable(evlist);
2321 }
2322
Jiri Olsae13798c2015-06-23 00:36:02 +02002323 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002324 evlist->threads->nr > 1 ||
2325 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002326again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002327 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002328
2329 for (i = 0; i < evlist->nr_mmaps; i++) {
2330 union perf_event *event;
2331
2332 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002334
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002335 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002336
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002337 err = perf_evlist__parse_sample(evlist, event, &sample);
2338 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002339 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002340 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002341 }
2342
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002343 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002344next_event:
2345 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002346
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002347 if (interrupted)
2348 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002349
2350 if (done && !draining) {
2351 perf_evlist__disable(evlist);
2352 draining = true;
2353 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002354 }
2355 }
2356
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002357 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002358 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002359
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002360 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2361 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2362 draining = true;
2363
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002364 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002365 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002366 } else {
2367 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002368 }
2369
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002370out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002371 thread__zput(trace->current);
2372
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002373 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002374
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002375 if (!err) {
2376 if (trace->summary)
2377 trace__fprintf_thread_summary(trace, trace->output);
2378
2379 if (trace->show_tool_stats) {
2380 fprintf(trace->output, "Stats:\n "
2381 " vfs_getname : %" PRIu64 "\n"
2382 " proc_getname: %" PRIu64 "\n",
2383 trace->stats.vfs_getname,
2384 trace->stats.proc_getname);
2385 }
2386 }
David Ahernbf2575c2013-10-08 21:26:53 -06002387
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002388out_delete_evlist:
2389 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002390 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002391 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002393{
2394 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002395
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002396out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002397 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002398 goto out_error;
2399
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002400out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002401 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002402 goto out_error;
2403
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002404out_error_mmap:
2405 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2406 goto out_error;
2407
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002408out_error_open:
2409 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2410
2411out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002412 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302413 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002414
2415out_error_apply_filters:
2416 fprintf(trace->output,
2417 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2418 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002419 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002420 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002421}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002422out_error_mem:
2423 fprintf(trace->output, "Not enough memory to run!\n");
2424 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002425
2426out_errno:
2427 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2428 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002429}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002430
David Ahern6810fc92013-08-28 22:29:52 -06002431static int trace__replay(struct trace *trace)
2432{
2433 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002434 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002435 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002436 struct perf_data_file file = {
2437 .path = input_name,
2438 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002439 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002440 };
David Ahern6810fc92013-08-28 22:29:52 -06002441 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002442 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002443 int err = -1;
2444
2445 trace->tool.sample = trace__process_sample;
2446 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002447 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002448 trace->tool.comm = perf_event__process_comm;
2449 trace->tool.exit = perf_event__process_exit;
2450 trace->tool.fork = perf_event__process_fork;
2451 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302452 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002453 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302454 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002455
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002456 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002457 trace->tool.ordering_requires_timestamps = true;
2458
2459 /* add tid to output */
2460 trace->multiple_threads = true;
2461
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002462 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002463 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002464 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002465
David Ahernaa07df62016-11-25 09:29:52 -07002466 if (trace->opts.target.pid)
2467 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2468
2469 if (trace->opts.target.tid)
2470 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2471
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002472 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002473 goto out;
2474
David Ahern8fb598e2013-09-28 13:13:00 -06002475 trace->host = &session->machines.host;
2476
David Ahern6810fc92013-08-28 22:29:52 -06002477 err = perf_session__set_tracepoints_handlers(session, handlers);
2478 if (err)
2479 goto out;
2480
Namhyung Kim003824e2013-11-12 15:25:00 +09002481 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2482 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002483 /* older kernels have syscalls tp versus raw_syscalls */
2484 if (evsel == NULL)
2485 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2486 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002487
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002488 if (evsel &&
2489 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2490 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002491 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2492 goto out;
2493 }
2494
2495 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2496 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002497 if (evsel == NULL)
2498 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2499 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002500 if (evsel &&
2501 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2502 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002503 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002504 goto out;
2505 }
2506
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002507 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002508 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2509 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2510 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2511 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2512 evsel->handler = trace__pgfault;
2513 }
2514
David Ahern6810fc92013-08-28 22:29:52 -06002515 setup_pager();
2516
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002517 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002518 if (err)
2519 pr_err("Failed to process events, error %d", err);
2520
David Ahernbf2575c2013-10-08 21:26:53 -06002521 else if (trace->summary)
2522 trace__fprintf_thread_summary(trace, trace->output);
2523
David Ahern6810fc92013-08-28 22:29:52 -06002524out:
2525 perf_session__delete(session);
2526
2527 return err;
2528}
2529
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002530static size_t trace__fprintf_threads_header(FILE *fp)
2531{
2532 size_t printed;
2533
Pekka Enberg99ff7152013-11-12 16:42:14 +02002534 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002535
2536 return printed;
2537}
2538
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002539DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2540 struct stats *stats;
2541 double msecs;
2542 int syscall;
2543)
2544{
2545 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2546 struct stats *stats = source->priv;
2547
2548 entry->syscall = source->i;
2549 entry->stats = stats;
2550 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2551}
2552
David Ahernbf2575c2013-10-08 21:26:53 -06002553static size_t thread__dump_stats(struct thread_trace *ttrace,
2554 struct trace *trace, FILE *fp)
2555{
David Ahernbf2575c2013-10-08 21:26:53 -06002556 size_t printed = 0;
2557 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002558 struct rb_node *nd;
2559 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002560
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002561 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002562 return 0;
2563
2564 printed += fprintf(fp, "\n");
2565
Milian Wolff834fd462015-08-06 11:24:29 +02002566 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2567 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2568 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002569
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002570 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002571 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002572 if (stats) {
2573 double min = (double)(stats->min) / NSEC_PER_MSEC;
2574 double max = (double)(stats->max) / NSEC_PER_MSEC;
2575 double avg = avg_stats(stats);
2576 double pct;
2577 u64 n = (u64) stats->n;
2578
2579 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2580 avg /= NSEC_PER_MSEC;
2581
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002582 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002583 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002584 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002585 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002586 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002587 }
David Ahernbf2575c2013-10-08 21:26:53 -06002588 }
2589
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002590 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002591 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002592
2593 return printed;
2594}
2595
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002596static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002597{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002598 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002599 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002600 double ratio;
2601
2602 if (ttrace == NULL)
2603 return 0;
2604
2605 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2606
Pekka Enberg15e65c62013-11-14 18:43:30 +02002607 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002608 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002609 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002610 if (ttrace->pfmaj)
2611 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2612 if (ttrace->pfmin)
2613 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002614 if (trace->sched)
2615 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2616 else if (fputc('\n', fp) != EOF)
2617 ++printed;
2618
David Ahernbf2575c2013-10-08 21:26:53 -06002619 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002620
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002621 return printed;
2622}
David Ahern896cbb52013-09-28 13:12:59 -06002623
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002624static unsigned long thread__nr_events(struct thread_trace *ttrace)
2625{
2626 return ttrace ? ttrace->nr_events : 0;
2627}
2628
2629DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2630 struct thread *thread;
2631)
2632{
2633 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002634}
2635
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002636static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2637{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002638 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2639 size_t printed = trace__fprintf_threads_header(fp);
2640 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002641
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002642 if (threads == NULL) {
2643 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2644 return 0;
2645 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002646
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002647 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002648 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2649
2650 resort_rb__delete(threads);
2651
2652 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002653}
2654
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002655static int trace__set_duration(const struct option *opt, const char *str,
2656 int unset __maybe_unused)
2657{
2658 struct trace *trace = opt->value;
2659
2660 trace->duration_filter = atof(str);
2661 return 0;
2662}
2663
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002664static int trace__set_filter_pids(const struct option *opt, const char *str,
2665 int unset __maybe_unused)
2666{
2667 int ret = -1;
2668 size_t i;
2669 struct trace *trace = opt->value;
2670 /*
2671 * FIXME: introduce a intarray class, plain parse csv and create a
2672 * { int nr, int entries[] } struct...
2673 */
2674 struct intlist *list = intlist__new(str);
2675
2676 if (list == NULL)
2677 return -1;
2678
2679 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2680 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2681
2682 if (trace->filter_pids.entries == NULL)
2683 goto out;
2684
2685 trace->filter_pids.entries[0] = getpid();
2686
2687 for (i = 1; i < trace->filter_pids.nr; ++i)
2688 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2689
2690 intlist__delete(list);
2691 ret = 0;
2692out:
2693 return ret;
2694}
2695
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002696static int trace__open_output(struct trace *trace, const char *filename)
2697{
2698 struct stat st;
2699
2700 if (!stat(filename, &st) && st.st_size) {
2701 char oldname[PATH_MAX];
2702
2703 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2704 unlink(oldname);
2705 rename(filename, oldname);
2706 }
2707
2708 trace->output = fopen(filename, "w");
2709
2710 return trace->output == NULL ? -errno : 0;
2711}
2712
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002713static int parse_pagefaults(const struct option *opt, const char *str,
2714 int unset __maybe_unused)
2715{
2716 int *trace_pgfaults = opt->value;
2717
2718 if (strcmp(str, "all") == 0)
2719 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2720 else if (strcmp(str, "maj") == 0)
2721 *trace_pgfaults |= TRACE_PFMAJ;
2722 else if (strcmp(str, "min") == 0)
2723 *trace_pgfaults |= TRACE_PFMIN;
2724 else
2725 return -1;
2726
2727 return 0;
2728}
2729
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002730static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2731{
2732 struct perf_evsel *evsel;
2733
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002734 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002735 evsel->handler = handler;
2736}
2737
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002738/*
2739 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2740 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2741 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2742 *
2743 * It'd be better to introduce a parse_options() variant that would return a
2744 * list with the terms it didn't match to an event...
2745 */
2746static int trace__parse_events_option(const struct option *opt, const char *str,
2747 int unset __maybe_unused)
2748{
2749 struct trace *trace = (struct trace *)opt->value;
2750 const char *s = str;
2751 char *sep = NULL, *lists[2] = { NULL, NULL, };
2752 int len = strlen(str), err = -1, list;
2753 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2754 char group_name[PATH_MAX];
2755
2756 if (strace_groups_dir == NULL)
2757 return -1;
2758
2759 if (*s == '!') {
2760 ++s;
2761 trace->not_ev_qualifier = true;
2762 }
2763
2764 while (1) {
2765 if ((sep = strchr(s, ',')) != NULL)
2766 *sep = '\0';
2767
2768 list = 0;
2769 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2770 list = 1;
2771 } else {
2772 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2773 if (access(group_name, R_OK) == 0)
2774 list = 1;
2775 }
2776
2777 if (lists[list]) {
2778 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2779 } else {
2780 lists[list] = malloc(len);
2781 if (lists[list] == NULL)
2782 goto out;
2783 strcpy(lists[list], s);
2784 }
2785
2786 if (!sep)
2787 break;
2788
2789 *sep = ',';
2790 s = sep + 1;
2791 }
2792
2793 if (lists[1] != NULL) {
2794 struct strlist_config slist_config = {
2795 .dirname = strace_groups_dir,
2796 };
2797
2798 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2799 if (trace->ev_qualifier == NULL) {
2800 fputs("Not enough memory to parse event qualifier", trace->output);
2801 goto out;
2802 }
2803
2804 if (trace__validate_ev_qualifier(trace))
2805 goto out;
2806 }
2807
2808 err = 0;
2809
2810 if (lists[0]) {
2811 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2812 "event selector. use 'perf list' to list available events",
2813 parse_events_option);
2814 err = parse_events_option(&o, lists[0], 0);
2815 }
2816out:
2817 if (sep)
2818 *sep = ',';
2819
2820 return err;
2821}
2822
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002823int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002824{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002825 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002826 "perf trace [<options>] [<command>]",
2827 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002828 "perf trace record [<options>] [<command>]",
2829 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002830 NULL
2831 };
2832 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002833 .syscalls = {
2834 . max = -1,
2835 },
2836 .opts = {
2837 .target = {
2838 .uid = UINT_MAX,
2839 .uses_mmap = true,
2840 },
2841 .user_freq = UINT_MAX,
2842 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002843 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002844 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002845 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002846 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002847 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002848 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002849 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002850 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002851 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002852 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002853 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002854 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002855 OPT_CALLBACK('e', "event", &trace, "event",
2856 "event/syscall selector. use 'perf list' to list available events",
2857 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002858 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2859 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002860 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002861 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2862 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002863 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002864 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002865 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2866 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002867 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002868 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002869 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2870 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002871 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002872 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002873 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002874 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002875 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002876 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002877 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2878 "number of mmap data pages",
2879 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002880 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002881 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002882 OPT_CALLBACK(0, "duration", &trace, "float",
2883 "show only events with duration > N.M ms",
2884 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002885 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002886 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002887 OPT_BOOLEAN('T', "time", &trace.full_time,
2888 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002889 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2890 "Show only syscall summary with statistics"),
2891 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2892 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002893 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2894 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002895 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002896 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002897 OPT_CALLBACK(0, "call-graph", &trace.opts,
2898 "record_mode[,record_size]", record_callchain_help,
2899 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002900 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2901 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002902 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2903 "Set the minimum stack depth when parsing the callchain, "
2904 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002905 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2906 "Set the maximum stack depth when parsing the callchain, "
2907 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002908 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002909 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2910 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002911 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2912 "ms to wait before starting measurement after program "
2913 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002914 OPT_END()
2915 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002916 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002917 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002918 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002919 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002920 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002921
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002922 signal(SIGSEGV, sighandler_dump_stack);
2923 signal(SIGFPE, sighandler_dump_stack);
2924
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002925 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002926 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002927
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002928 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002929 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002930 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002931 goto out;
2932 }
2933
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002934 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2935 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002936
Wang Nand7888572016-04-08 15:07:24 +00002937 err = bpf__setup_stdout(trace.evlist);
2938 if (err) {
2939 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2940 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2941 goto out;
2942 }
2943
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002944 err = -1;
2945
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002946 if (trace.trace_pgfaults) {
2947 trace.opts.sample_address = true;
2948 trace.opts.sample_time = true;
2949 }
2950
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002951 if (trace.opts.mmap_pages == UINT_MAX)
2952 mmap_pages_user_set = false;
2953
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002954 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002955 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002956 max_stack_user_set = false;
2957 }
2958
2959#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002960 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002961 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2962#endif
2963
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002964 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002965 if (!mmap_pages_user_set && geteuid() == 0)
2966 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2967
Milian Wolff566a0882016-04-08 13:34:15 +02002968 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002969 }
Milian Wolff566a0882016-04-08 13:34:15 +02002970
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002971 if (trace.evlist->nr_entries > 0)
2972 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2973
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002974 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2975 return trace__record(&trace, argc-1, &argv[1]);
2976
2977 /* summary_only implies summary option, but don't overwrite summary if set */
2978 if (trace.summary_only)
2979 trace.summary = trace.summary_only;
2980
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002981 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2982 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002983 pr_err("Please specify something to trace.\n");
2984 return -1;
2985 }
2986
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002987 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002988 pr_err("The -e option can't be used with --no-syscalls.\n");
2989 goto out;
2990 }
2991
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002992 if (output_name != NULL) {
2993 err = trace__open_output(&trace, output_name);
2994 if (err < 0) {
2995 perror("failed to create output file");
2996 goto out;
2997 }
2998 }
2999
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003000 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3001
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003002 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003003 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003004 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003005 fprintf(trace.output, "%s", bf);
3006 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003007 }
3008
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003009 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003010 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003011 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003012 fprintf(trace.output, "%s", bf);
3013 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003014 }
3015
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003016 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003017 trace.opts.target.system_wide = true;
3018
David Ahern6810fc92013-08-28 22:29:52 -06003019 if (input_name)
3020 err = trace__replay(&trace);
3021 else
3022 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003023
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003024out_close:
3025 if (output_name != NULL)
3026 fclose(trace.output);
3027out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003028 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003029}