blob: 4b2a5d2981970baf86e4e458ef4ced256fc98c0e [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030024#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030025#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060026#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030027#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030028#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060029#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030030#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060031#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030032#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060033#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030034#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060035#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030036#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010037#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070038#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000039#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020040#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030041#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030042#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030043#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030044#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030045
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030046#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030047#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030048#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030049#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030050#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030052#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020053#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030054#include <linux/filter.h>
55#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030060
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030061#include "sane_ctype.h"
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef O_CLOEXEC
64# define O_CLOEXEC 02000000
65#endif
66
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030067struct trace {
68 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030069 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030070 struct {
71 int max;
72 struct syscall *table;
73 struct {
74 struct perf_evsel *sys_enter,
75 *sys_exit;
76 } events;
77 } syscalls;
78 struct record_opts opts;
79 struct perf_evlist *evlist;
80 struct machine *host;
81 struct thread *current;
82 u64 base_time;
83 FILE *output;
84 unsigned long nr_events;
85 struct strlist *ev_qualifier;
86 struct {
87 size_t nr;
88 int *entries;
89 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030090 struct {
91 size_t nr;
92 pid_t *entries;
93 } filter_pids;
94 double duration_filter;
95 double runtime_ms;
96 struct {
97 u64 vfs_getname,
98 proc_getname;
99 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300100 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300101 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300102 bool not_ev_qualifier;
103 bool live;
104 bool full_time;
105 bool sched;
106 bool multiple_threads;
107 bool summary;
108 bool summary_only;
109 bool show_comm;
110 bool show_tool_stats;
111 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300112 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300113 bool force;
114 bool vfs_getname;
115 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300116 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300118
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300119struct tp_field {
120 int offset;
121 union {
122 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
123 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
124 };
125};
126
127#define TP_UINT_FIELD(bits) \
128static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
129{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500130 u##bits value; \
131 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
132 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300133}
134
135TP_UINT_FIELD(8);
136TP_UINT_FIELD(16);
137TP_UINT_FIELD(32);
138TP_UINT_FIELD(64);
139
140#define TP_UINT_FIELD__SWAPPED(bits) \
141static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
142{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500143 u##bits value; \
144 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300145 return bswap_##bits(value);\
146}
147
148TP_UINT_FIELD__SWAPPED(16);
149TP_UINT_FIELD__SWAPPED(32);
150TP_UINT_FIELD__SWAPPED(64);
151
152static int tp_field__init_uint(struct tp_field *field,
153 struct format_field *format_field,
154 bool needs_swap)
155{
156 field->offset = format_field->offset;
157
158 switch (format_field->size) {
159 case 1:
160 field->integer = tp_field__u8;
161 break;
162 case 2:
163 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
164 break;
165 case 4:
166 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
167 break;
168 case 8:
169 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
170 break;
171 default:
172 return -1;
173 }
174
175 return 0;
176}
177
178static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
179{
180 return sample->raw_data + field->offset;
181}
182
183static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
184{
185 field->offset = format_field->offset;
186 field->pointer = tp_field__ptr;
187 return 0;
188}
189
190struct syscall_tp {
191 struct tp_field id;
192 union {
193 struct tp_field args, ret;
194 };
195};
196
197static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
198 struct tp_field *field,
199 const char *name)
200{
201 struct format_field *format_field = perf_evsel__field(evsel, name);
202
203 if (format_field == NULL)
204 return -1;
205
206 return tp_field__init_uint(field, format_field, evsel->needs_swap);
207}
208
209#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
210 ({ struct syscall_tp *sc = evsel->priv;\
211 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
212
213static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
214 struct tp_field *field,
215 const char *name)
216{
217 struct format_field *format_field = perf_evsel__field(evsel, name);
218
219 if (format_field == NULL)
220 return -1;
221
222 return tp_field__init_ptr(field, format_field);
223}
224
225#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
226 ({ struct syscall_tp *sc = evsel->priv;\
227 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
228
229static void perf_evsel__delete_priv(struct perf_evsel *evsel)
230{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300231 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300232 perf_evsel__delete(evsel);
233}
234
Namhyung Kim96695d42013-11-12 08:51:45 -0300235static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
236{
237 evsel->priv = malloc(sizeof(struct syscall_tp));
238 if (evsel->priv != NULL) {
239 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
240 goto out_delete;
241
242 evsel->handler = handler;
243 return 0;
244 }
245
246 return -ENOMEM;
247
248out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300249 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300250 return -ENOENT;
251}
252
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300253static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300254{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300255 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300256
David Ahern9aca7f12013-12-04 19:41:39 -0700257 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200258 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700259 evsel = perf_evsel__newtp("syscalls", direction);
260
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200261 if (IS_ERR(evsel))
262 return NULL;
263
264 if (perf_evsel__init_syscall_tp(evsel, handler))
265 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300266
267 return evsel;
268
269out_delete:
270 perf_evsel__delete_priv(evsel);
271 return NULL;
272}
273
274#define perf_evsel__sc_tp_uint(evsel, name, sample) \
275 ({ struct syscall_tp *fields = evsel->priv; \
276 fields->name.integer(&fields->name, sample); })
277
278#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
279 ({ struct syscall_tp *fields = evsel->priv; \
280 fields->name.pointer(&fields->name, sample); })
281
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300282struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300283 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300284 int nr_entries;
285 const char **entries;
286};
287
288#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
289 .nr_entries = ARRAY_SIZE(array), \
290 .entries = array, \
291}
292
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300293#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
294 .offset = off, \
295 .nr_entries = ARRAY_SIZE(array), \
296 .entries = array, \
297}
298
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300299static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
300 const char *intfmt,
301 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300304 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300305
306 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300307 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300308
309 return scnprintf(bf, size, "%s", sa->entries[idx]);
310}
311
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300312static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
313 struct syscall_arg *arg)
314{
315 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
316}
317
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300318#define SCA_STRARRAY syscall_arg__scnprintf_strarray
319
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300320#if defined(__i386__) || defined(__x86_64__)
321/*
322 * FIXME: Make this available to all arches as soon as the ioctl beautifier
323 * gets rewritten to support all arches.
324 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300325static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
326 struct syscall_arg *arg)
327{
328 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
329}
330
331#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300332#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300333
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300334static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
335 struct syscall_arg *arg);
336
337#define SCA_FD syscall_arg__scnprintf_fd
338
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300339#ifndef AT_FDCWD
340#define AT_FDCWD -100
341#endif
342
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300343static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
344 struct syscall_arg *arg)
345{
346 int fd = arg->val;
347
348 if (fd == AT_FDCWD)
349 return scnprintf(bf, size, "CWD");
350
351 return syscall_arg__scnprintf_fd(bf, size, arg);
352}
353
354#define SCA_FDAT syscall_arg__scnprintf_fd_at
355
356static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
357 struct syscall_arg *arg);
358
359#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
360
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300361static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300362 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300363{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300364 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300365}
366
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300367#define SCA_HEX syscall_arg__scnprintf_hex
368
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300369static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
370 struct syscall_arg *arg)
371{
372 return scnprintf(bf, size, "%d", arg->val);
373}
374
375#define SCA_INT syscall_arg__scnprintf_int
376
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300377static const char *bpf_cmd[] = {
378 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
379 "MAP_GET_NEXT_KEY", "PROG_LOAD",
380};
381static DEFINE_STRARRAY(bpf_cmd);
382
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300383static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
384static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300385
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300386static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
387static DEFINE_STRARRAY(itimers);
388
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300389static const char *keyctl_options[] = {
390 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
391 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
392 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
393 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
394 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
395};
396static DEFINE_STRARRAY(keyctl_options);
397
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300398static const char *whences[] = { "SET", "CUR", "END",
399#ifdef SEEK_DATA
400"DATA",
401#endif
402#ifdef SEEK_HOLE
403"HOLE",
404#endif
405};
406static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300407
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300408static const char *fcntl_cmds[] = {
409 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
410 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
411 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
412 "F_GETOWNER_UIDS",
413};
414static DEFINE_STRARRAY(fcntl_cmds);
415
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300416static const char *rlimit_resources[] = {
417 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
418 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
419 "RTTIME",
420};
421static DEFINE_STRARRAY(rlimit_resources);
422
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300423static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
424static DEFINE_STRARRAY(sighow);
425
David Ahern4f8c1b72013-09-22 19:45:00 -0600426static const char *clockid[] = {
427 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300428 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
429 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600430};
431static DEFINE_STRARRAY(clockid);
432
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300433static const char *socket_families[] = {
434 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
435 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
436 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
437 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
438 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
439 "ALG", "NFC", "VSOCK",
440};
441static DEFINE_STRARRAY(socket_families);
442
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300443static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
444 struct syscall_arg *arg)
445{
446 size_t printed = 0;
447 int mode = arg->val;
448
449 if (mode == F_OK) /* 0 */
450 return scnprintf(bf, size, "F");
451#define P_MODE(n) \
452 if (mode & n##_OK) { \
453 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
454 mode &= ~n##_OK; \
455 }
456
457 P_MODE(R);
458 P_MODE(W);
459 P_MODE(X);
460#undef P_MODE
461
462 if (mode)
463 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
464
465 return printed;
466}
467
468#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
469
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300470static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
471 struct syscall_arg *arg);
472
473#define SCA_FILENAME syscall_arg__scnprintf_filename
474
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300475static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
476 struct syscall_arg *arg)
477{
478 int printed = 0, flags = arg->val;
479
480#define P_FLAG(n) \
481 if (flags & O_##n) { \
482 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
483 flags &= ~O_##n; \
484 }
485
486 P_FLAG(CLOEXEC);
487 P_FLAG(NONBLOCK);
488#undef P_FLAG
489
490 if (flags)
491 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
492
493 return printed;
494}
495
496#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
497
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300498#if defined(__i386__) || defined(__x86_64__)
499/*
500 * FIXME: Make this available to all arches.
501 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300502#define TCGETS 0x5401
503
504static const char *tioctls[] = {
505 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
506 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
507 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
508 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
509 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
510 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
511 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
512 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
513 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
514 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
515 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
516 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
517 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
518 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
519 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
520};
521
522static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300523#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300524
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300525#ifndef GRND_NONBLOCK
526#define GRND_NONBLOCK 0x0001
527#endif
528#ifndef GRND_RANDOM
529#define GRND_RANDOM 0x0002
530#endif
531
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300532static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
533 struct syscall_arg *arg)
534{
535 int printed = 0, flags = arg->val;
536
537#define P_FLAG(n) \
538 if (flags & GRND_##n) { \
539 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
540 flags &= ~GRND_##n; \
541 }
542
543 P_FLAG(RANDOM);
544 P_FLAG(NONBLOCK);
545#undef P_FLAG
546
547 if (flags)
548 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
549
550 return printed;
551}
552
553#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
554
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300555#define STRARRAY(arg, name, array) \
556 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
557 .arg_parm = { [arg] = &strarray__##array, }
558
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300559#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300560#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300561#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300562#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300563#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300564#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300565#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300566#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300567#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300568#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300569#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300570#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300571#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300572#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300573
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300574static struct syscall_fmt {
575 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300576 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300577 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300578 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300579 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300580 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300581 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300582 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300583} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300584 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300585 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300586 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300587 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300588 { .name = "brk", .hexret = true,
589 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300590 { .name = "chdir", .errmsg = true, },
591 { .name = "chmod", .errmsg = true, },
592 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600593 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300594 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300595 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300596 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300597 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300598 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300599 { .name = "dup", .errmsg = true, },
600 { .name = "dup2", .errmsg = true, },
601 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300602 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300603 { .name = "eventfd2", .errmsg = true,
604 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300605 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300606 { .name = "fadvise64", .errmsg = true, },
607 { .name = "fallocate", .errmsg = true, },
608 { .name = "fchdir", .errmsg = true, },
609 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300610 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300611 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300612 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300613 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300614 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300615 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300616 .arg_scnprintf = { [1] = SCA_STRARRAY, /* cmd */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300617 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300618 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300619 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300620 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
621 { .name = "fsetxattr", .errmsg = true, },
622 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300623 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300624 { .name = "fstatfs", .errmsg = true, },
625 { .name = "fsync", .errmsg = true, },
626 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300627 { .name = "futex", .errmsg = true,
628 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300629 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300630 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300631 { .name = "getdents", .errmsg = true, },
632 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300633 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300634 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300635 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300636 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300637 { .name = "getrandom", .errmsg = true,
638 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300639 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300640 { .name = "getxattr", .errmsg = true, },
641 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300642 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300643 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300644#if defined(__i386__) || defined(__x86_64__)
645/*
646 * FIXME: Make this available to all arches.
647 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300648 [1] = SCA_STRHEXARRAY, /* cmd */
649 [2] = SCA_HEX, /* arg */ },
650 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300651#else
652 [2] = SCA_HEX, /* arg */ }, },
653#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300654 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300655 { .name = "kill", .errmsg = true,
656 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300657 { .name = "lchown", .errmsg = true, },
658 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300659 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300660 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300661 { .name = "listxattr", .errmsg = true, },
662 { .name = "llistxattr", .errmsg = true, },
663 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300664 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300665 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300666 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300667 { .name = "lsetxattr", .errmsg = true, },
668 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
669 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300670 { .name = "madvise", .errmsg = true,
671 .arg_scnprintf = { [0] = SCA_HEX, /* start */
672 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300673 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300674 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300675 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
676 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300677 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300678 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300679 { .name = "mlock", .errmsg = true,
680 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
681 { .name = "mlockall", .errmsg = true,
682 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300683 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200684/* The standard mmap maps to old_mmap on s390x */
685#if defined(__s390x__)
686 .alias = "old_mmap",
687#endif
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300688 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300689 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300690 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300691 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300692 .arg_scnprintf = { [0] = SCA_HEX, /* start */
693 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300694 { .name = "mq_unlink", .errmsg = true,
695 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300696 { .name = "mremap", .hexret = true,
697 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300698 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300699 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300700 { .name = "munlock", .errmsg = true,
701 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300702 { .name = "munmap", .errmsg = true,
703 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300704 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300705 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300706 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300707 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300708 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300709 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300710 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300711 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
712 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300713 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300714 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
715 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300716 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300717 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300718 [3] = SCA_FD, /* group_fd */
719 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300720 { .name = "pipe2", .errmsg = true,
721 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300722 { .name = "poll", .errmsg = true, .timeout = true, },
723 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300724 { .name = "pread", .errmsg = true, .alias = "pread64", },
725 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300726 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300727 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
728 { .name = "pwritev", .errmsg = true, },
729 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300730 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300731 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300732 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300733 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300734 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300735 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300736 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300737 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300738 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300739 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300740 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300741 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300742 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300743 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300744 { .name = "rt_sigaction", .errmsg = true,
745 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300746 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300747 { .name = "rt_sigqueueinfo", .errmsg = true,
748 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
749 { .name = "rt_tgsigqueueinfo", .errmsg = true,
750 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300751 { .name = "sched_getattr", .errmsg = true, },
752 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300753 { .name = "sched_setscheduler", .errmsg = true,
754 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300755 { .name = "seccomp", .errmsg = true,
756 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
757 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300758 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300759 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300760 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300761 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300762 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300763 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300764 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300765 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300766 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300767 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300768 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300769 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300770 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300771 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300772 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
773 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300774 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300775 { .name = "socketpair", .errmsg = true,
776 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
777 [1] = SCA_SK_TYPE, /* type */ },
778 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300779 { .name = "stat", .errmsg = true, .alias = "newstat", },
780 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300781 { .name = "statx", .errmsg = true,
782 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
783 [2] = SCA_STATX_FLAGS, /* flags */
784 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300785 { .name = "swapoff", .errmsg = true,
786 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
787 { .name = "swapon", .errmsg = true,
788 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300789 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300790 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300791 { .name = "tgkill", .errmsg = true,
792 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
793 { .name = "tkill", .errmsg = true,
794 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300795 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300796 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300797 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300798 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
799 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300800 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300801 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
802 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300803 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300804 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300805 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300806 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300807 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300808 { .name = "write", .errmsg = true, },
809 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300810};
811
812static int syscall_fmt__cmp(const void *name, const void *fmtp)
813{
814 const struct syscall_fmt *fmt = fmtp;
815 return strcmp(name, fmt->name);
816}
817
818static struct syscall_fmt *syscall_fmt__find(const char *name)
819{
820 const int nmemb = ARRAY_SIZE(syscall_fmts);
821 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
822}
823
824struct syscall {
825 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300826 int nr_args;
827 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300828 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300829 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300830 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300831 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300832 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300833};
834
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300835/*
836 * We need to have this 'calculated' boolean because in some cases we really
837 * don't know what is the duration of a syscall, for instance, when we start
838 * a session and some threads are waiting for a syscall to finish, say 'poll',
839 * in which case all we can do is to print "( ? ) for duration and for the
840 * start timestamp.
841 */
842static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200843{
844 double duration = (double)t / NSEC_PER_MSEC;
845 size_t printed = fprintf(fp, "(");
846
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300847 if (!calculated)
848 printed += fprintf(fp, " ? ");
849 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200850 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
851 else if (duration >= 0.01)
852 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
853 else
854 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300855 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200856}
857
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300858/**
859 * filename.ptr: The filename char pointer that will be vfs_getname'd
860 * filename.entry_str_pos: Where to insert the string translated from
861 * filename.ptr by the vfs_getname tracepoint/kprobe.
862 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300863struct thread_trace {
864 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300865 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300866 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400867 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300868 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300869 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300870 struct {
871 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300872 short int entry_str_pos;
873 bool pending_open;
874 unsigned int namelen;
875 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300876 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300877 struct {
878 int max;
879 char **table;
880 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600881
882 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300883};
884
885static struct thread_trace *thread_trace__new(void)
886{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300887 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
888
889 if (ttrace)
890 ttrace->paths.max = -1;
891
David Ahernbf2575c2013-10-08 21:26:53 -0600892 ttrace->syscall_stats = intlist__new(NULL);
893
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300894 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895}
896
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300897static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300898{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300899 struct thread_trace *ttrace;
900
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300901 if (thread == NULL)
902 goto fail;
903
Namhyung Kim89dceb22014-10-06 09:46:03 +0900904 if (thread__priv(thread) == NULL)
905 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300906
Namhyung Kim89dceb22014-10-06 09:46:03 +0900907 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300908 goto fail;
909
Namhyung Kim89dceb22014-10-06 09:46:03 +0900910 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300911 ++ttrace->nr_events;
912
913 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300914fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300915 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300916 "WARNING: not enough memory, dropping samples!\n");
917 return NULL;
918}
919
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400920#define TRACE_PFMAJ (1 << 0)
921#define TRACE_PFMIN (1 << 1)
922
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300923static const size_t trace__entry_str_size = 2048;
924
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300925static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900927 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300928
929 if (fd > ttrace->paths.max) {
930 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
931
932 if (npath == NULL)
933 return -1;
934
935 if (ttrace->paths.max != -1) {
936 memset(npath + ttrace->paths.max + 1, 0,
937 (fd - ttrace->paths.max) * sizeof(char *));
938 } else {
939 memset(npath, 0, (fd + 1) * sizeof(char *));
940 }
941
942 ttrace->paths.table = npath;
943 ttrace->paths.max = fd;
944 }
945
946 ttrace->paths.table[fd] = strdup(pathname);
947
948 return ttrace->paths.table[fd] != NULL ? 0 : -1;
949}
950
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300951static int thread__read_fd_path(struct thread *thread, int fd)
952{
953 char linkname[PATH_MAX], pathname[PATH_MAX];
954 struct stat st;
955 int ret;
956
957 if (thread->pid_ == thread->tid) {
958 scnprintf(linkname, sizeof(linkname),
959 "/proc/%d/fd/%d", thread->pid_, fd);
960 } else {
961 scnprintf(linkname, sizeof(linkname),
962 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
963 }
964
965 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
966 return -1;
967
968 ret = readlink(linkname, pathname, sizeof(pathname));
969
970 if (ret < 0 || ret > st.st_size)
971 return -1;
972
973 pathname[ret] = '\0';
974 return trace__set_fd_pathname(thread, fd, pathname);
975}
976
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300977static const char *thread__fd_path(struct thread *thread, int fd,
978 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300979{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900980 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981
982 if (ttrace == NULL)
983 return NULL;
984
985 if (fd < 0)
986 return NULL;
987
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300988 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300989 if (!trace->live)
990 return NULL;
991 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300992 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300993 return NULL;
994 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300995
996 return ttrace->paths.table[fd];
997}
998
999static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1000 struct syscall_arg *arg)
1001{
1002 int fd = arg->val;
1003 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001004 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001005
1006 if (path)
1007 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1008
1009 return printed;
1010}
1011
1012static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1013 struct syscall_arg *arg)
1014{
1015 int fd = arg->val;
1016 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001017 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001018
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001019 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1020 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021
1022 return printed;
1023}
1024
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001025static void thread__set_filename_pos(struct thread *thread, const char *bf,
1026 unsigned long ptr)
1027{
1028 struct thread_trace *ttrace = thread__priv(thread);
1029
1030 ttrace->filename.ptr = ptr;
1031 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1032}
1033
1034static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1035 struct syscall_arg *arg)
1036{
1037 unsigned long ptr = arg->val;
1038
1039 if (!arg->trace->vfs_getname)
1040 return scnprintf(bf, size, "%#x", ptr);
1041
1042 thread__set_filename_pos(arg->thread, bf, ptr);
1043 return 0;
1044}
1045
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001046static bool trace__filter_duration(struct trace *trace, double t)
1047{
1048 return t < (trace->duration_filter * NSEC_PER_MSEC);
1049}
1050
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001051static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001052{
1053 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1054
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001055 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001056}
1057
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001058/*
1059 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1060 * using ttrace->entry_time for a thread that receives a sys_exit without
1061 * first having received a sys_enter ("poll" issued before tracing session
1062 * starts, lost sys_enter exit due to ring buffer overflow).
1063 */
1064static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1065{
1066 if (tstamp > 0)
1067 return __trace__fprintf_tstamp(trace, tstamp, fp);
1068
1069 return fprintf(fp, " ? ");
1070}
1071
Namhyung Kimf15eb532012-10-05 14:02:16 +09001072static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001073static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001074
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001075static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001076{
1077 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001078 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001079}
1080
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001081static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001082 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001083{
1084 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001085 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001087 if (trace->multiple_threads) {
1088 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001089 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001090 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001091 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001092
1093 return printed;
1094}
1095
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001096static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001097 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098{
1099 int ret = 0;
1100
1101 switch (event->header.type) {
1102 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001103 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001105 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001106 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001108 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109 break;
1110 }
1111
1112 return ret;
1113}
1114
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001115static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001116 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001117 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001118 struct machine *machine)
1119{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001120 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001121 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122}
1123
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001124static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1125{
1126 struct machine *machine = vmachine;
1127
1128 if (machine->kptr_restrict_warned)
1129 return NULL;
1130
1131 if (symbol_conf.kptr_restrict) {
1132 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1133 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1134 "Kernel samples will not be resolved.\n");
1135 machine->kptr_restrict_warned = true;
1136 return NULL;
1137 }
1138
1139 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1140}
1141
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001142static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1143{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001144 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145
1146 if (err)
1147 return err;
1148
David Ahern8fb598e2013-09-28 13:13:00 -06001149 trace->host = machine__new_host();
1150 if (trace->host == NULL)
1151 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001152
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001153 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001154 return -errno;
1155
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001156 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001157 evlist->threads, trace__tool_process, false,
1158 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001159 if (err)
1160 symbol__exit();
1161
1162 return err;
1163}
1164
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001165static int syscall__set_arg_fmts(struct syscall *sc)
1166{
1167 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001168 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001169
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001170 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001171 if (sc->arg_scnprintf == NULL)
1172 return -1;
1173
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001174 if (sc->fmt)
1175 sc->arg_parm = sc->fmt->arg_parm;
1176
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001177 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001178 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1179 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001180 else if (strcmp(field->type, "const char *") == 0 &&
1181 (strcmp(field->name, "filename") == 0 ||
1182 strcmp(field->name, "path") == 0 ||
1183 strcmp(field->name, "pathname") == 0))
1184 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001185 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001186 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001187 else if (strcmp(field->type, "pid_t") == 0)
1188 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001189 else if (strcmp(field->type, "umode_t") == 0)
1190 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001191 else if ((strcmp(field->type, "int") == 0 ||
1192 strcmp(field->type, "unsigned int") == 0 ||
1193 strcmp(field->type, "long") == 0) &&
1194 (len = strlen(field->name)) >= 2 &&
1195 strcmp(field->name + len - 2, "fd") == 0) {
1196 /*
1197 * /sys/kernel/tracing/events/syscalls/sys_enter*
1198 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1199 * 65 int
1200 * 23 unsigned int
1201 * 7 unsigned long
1202 */
1203 sc->arg_scnprintf[idx] = SCA_FD;
1204 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001205 ++idx;
1206 }
1207
1208 return 0;
1209}
1210
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001211static int trace__read_syscall_info(struct trace *trace, int id)
1212{
1213 char tp_name[128];
1214 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001215 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001216
1217 if (name == NULL)
1218 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001219
1220 if (id > trace->syscalls.max) {
1221 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1222
1223 if (nsyscalls == NULL)
1224 return -1;
1225
1226 if (trace->syscalls.max != -1) {
1227 memset(nsyscalls + trace->syscalls.max + 1, 0,
1228 (id - trace->syscalls.max) * sizeof(*sc));
1229 } else {
1230 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1231 }
1232
1233 trace->syscalls.table = nsyscalls;
1234 trace->syscalls.max = id;
1235 }
1236
1237 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001238 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001239
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001240 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001241
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001242 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001243 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001244
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001245 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001246 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001247 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001248 }
1249
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001250 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001251 return -1;
1252
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001253 sc->args = sc->tp_format->format.fields;
1254 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001255 /*
1256 * We need to check and discard the first variable '__syscall_nr'
1257 * or 'nr' that mean the syscall number. It is needless here.
1258 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1259 */
1260 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001261 sc->args = sc->args->next;
1262 --sc->nr_args;
1263 }
1264
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001265 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1266
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001267 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001268}
1269
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001270static int trace__validate_ev_qualifier(struct trace *trace)
1271{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001272 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001273 struct str_node *pos;
1274
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001275 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1276 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1277 sizeof(trace->ev_qualifier_ids.entries[0]));
1278
1279 if (trace->ev_qualifier_ids.entries == NULL) {
1280 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1281 trace->output);
1282 err = -EINVAL;
1283 goto out;
1284 }
1285
1286 i = 0;
1287
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001288 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001289 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001290 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001291
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001292 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001293 if (err == 0) {
1294 fputs("Error:\tInvalid syscall ", trace->output);
1295 err = -EINVAL;
1296 } else {
1297 fputs(", ", trace->output);
1298 }
1299
1300 fputs(sc, trace->output);
1301 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001302
1303 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001304 }
1305
1306 if (err < 0) {
1307 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1308 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001309 zfree(&trace->ev_qualifier_ids.entries);
1310 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001311 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001312out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001313 return err;
1314}
1315
David Ahern55d43bc2015-02-19 15:00:22 -05001316/*
1317 * args is to be interpreted as a series of longs but we need to handle
1318 * 8-byte unaligned accesses. args points to raw_data within the event
1319 * and raw_data is guaranteed to be 8-byte unaligned because it is
1320 * preceded by raw_size which is a u32. So we need to copy args to a temp
1321 * variable to read it. Most notably this avoids extended load instructions
1322 * on unaligned addresses
1323 */
1324
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001325static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001326 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001327 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001328{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001329 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001330 unsigned char *p;
1331 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001332
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001333 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001334 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001335 u8 bit = 1;
1336 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001337 .idx = 0,
1338 .mask = 0,
1339 .trace = trace,
1340 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001341 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001342
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001343 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001344 field = field->next, ++arg.idx, bit <<= 1) {
1345 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001346 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001347
1348 /* special care for unaligned accesses */
1349 p = args + sizeof(unsigned long) * arg.idx;
1350 memcpy(&val, p, sizeof(val));
1351
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001352 /*
1353 * Suppress this argument if its value is zero and
1354 * and we don't have a string associated in an
1355 * strarray for it.
1356 */
David Ahern55d43bc2015-02-19 15:00:22 -05001357 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001358 !(sc->arg_scnprintf &&
1359 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1360 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001361 continue;
1362
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001363 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001364 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001365 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bc2015-02-19 15:00:22 -05001366 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001367 if (sc->arg_parm)
1368 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001369 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1370 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001371 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001372 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bc2015-02-19 15:00:22 -05001373 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001374 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001375 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001376 } else if (IS_ERR(sc->tp_format)) {
1377 /*
1378 * If we managed to read the tracepoint /format file, then we
1379 * may end up not having any args, like with gettid(), so only
1380 * print the raw args when we didn't manage to read it.
1381 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001382 int i = 0;
1383
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001384 while (i < 6) {
David Ahern55d43bc2015-02-19 15:00:22 -05001385 /* special care for unaligned accesses */
1386 p = args + sizeof(unsigned long) * i;
1387 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001388 printed += scnprintf(bf + printed, size - printed,
1389 "%sarg%d: %ld",
David Ahern55d43bc2015-02-19 15:00:22 -05001390 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391 ++i;
1392 }
1393 }
1394
1395 return printed;
1396}
1397
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001398typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001399 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001400 struct perf_sample *sample);
1401
1402static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001403 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001404{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001405
1406 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001407
1408 /*
1409 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1410 * before that, leaving at a higher verbosity level till that is
1411 * explained. Reproduced with plain ftrace with:
1412 *
1413 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1414 * grep "NR -1 " /t/trace_pipe
1415 *
1416 * After generating some load on the machine.
1417 */
1418 if (verbose > 1) {
1419 static u64 n;
1420 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1421 id, perf_evsel__name(evsel), ++n);
1422 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001423 return NULL;
1424 }
1425
1426 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1427 trace__read_syscall_info(trace, id))
1428 goto out_cant_read;
1429
1430 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1431 goto out_cant_read;
1432
1433 return &trace->syscalls.table[id];
1434
1435out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001436 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001437 fprintf(trace->output, "Problems reading syscall %d", id);
1438 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1439 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1440 fputs(" information\n", trace->output);
1441 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001442 return NULL;
1443}
1444
David Ahernbf2575c2013-10-08 21:26:53 -06001445static void thread__update_stats(struct thread_trace *ttrace,
1446 int id, struct perf_sample *sample)
1447{
1448 struct int_node *inode;
1449 struct stats *stats;
1450 u64 duration = 0;
1451
1452 inode = intlist__findnew(ttrace->syscall_stats, id);
1453 if (inode == NULL)
1454 return;
1455
1456 stats = inode->priv;
1457 if (stats == NULL) {
1458 stats = malloc(sizeof(struct stats));
1459 if (stats == NULL)
1460 return;
1461 init_stats(stats);
1462 inode->priv = stats;
1463 }
1464
1465 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1466 duration = sample->time - ttrace->entry_time;
1467
1468 update_stats(stats, duration);
1469}
1470
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001471static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1472{
1473 struct thread_trace *ttrace;
1474 u64 duration;
1475 size_t printed;
1476
1477 if (trace->current == NULL)
1478 return 0;
1479
1480 ttrace = thread__priv(trace->current);
1481
1482 if (!ttrace->entry_pending)
1483 return 0;
1484
1485 duration = sample->time - ttrace->entry_time;
1486
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001487 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001488 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1489 ttrace->entry_pending = false;
1490
1491 return printed;
1492}
1493
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001494static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001495 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001496 struct perf_sample *sample)
1497{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001498 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001499 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001500 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001501 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001502 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001503 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001504 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001505
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001506 if (sc == NULL)
1507 return -1;
1508
David Ahern8fb598e2013-09-28 13:13:00 -06001509 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001510 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001511 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001512 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001513
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001514 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001515
1516 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001517 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001518 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001519 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 }
1521
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001522 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001523 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001524
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001525 ttrace->entry_time = sample->time;
1526 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001527 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001528
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001529 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001530 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001531
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001532 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001533 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001534 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001535 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001536 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001537 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001538 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001539 /* See trace__vfs_getname & trace__sys_exit */
1540 ttrace->filename.pending_open = false;
1541 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001542
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001543 if (trace->current != thread) {
1544 thread__put(trace->current);
1545 trace->current = thread__get(thread);
1546 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001547 err = 0;
1548out_put:
1549 thread__put(thread);
1550 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001551}
1552
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001553static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1554 struct perf_sample *sample,
1555 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001556{
1557 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001558
1559 if (machine__resolve(trace->host, &al, sample) < 0 ||
1560 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1561 return -1;
1562
1563 return 0;
1564}
1565
1566static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1567{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001568 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001569 const unsigned int print_opts = EVSEL__PRINT_SYM |
1570 EVSEL__PRINT_DSO |
1571 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001572
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001573 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001574}
1575
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001576static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001577 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001578 struct perf_sample *sample)
1579{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001580 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001581 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001582 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001583 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001584 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001585 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001586 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001587
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001588 if (sc == NULL)
1589 return -1;
1590
David Ahern8fb598e2013-09-28 13:13:00 -06001591 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001592 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001593 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001594 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001595
David Ahernbf2575c2013-10-08 21:26:53 -06001596 if (trace->summary)
1597 thread__update_stats(ttrace, id, sample);
1598
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001599 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001600
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001601 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001602 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1603 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001604 ++trace->stats.vfs_getname;
1605 }
1606
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001607 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001608 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001609 if (trace__filter_duration(trace, duration))
1610 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001611 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001612 } else if (trace->duration_filter)
1613 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001614
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001615 if (sample->callchain) {
1616 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1617 if (callchain_ret == 0) {
1618 if (callchain_cursor.nr < trace->min_stack)
1619 goto out;
1620 callchain_ret = 1;
1621 }
1622 }
1623
David Ahernfd2eaba2013-11-12 09:31:15 -07001624 if (trace->summary_only)
1625 goto out;
1626
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001627 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001628
1629 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001630 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001631 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001632 fprintf(trace->output, " ... [");
1633 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1634 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001635 }
1636
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001637 if (sc->fmt == NULL) {
1638signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001639 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001640 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001641 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001642 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001643 *e = audit_errno_to_name(-ret);
1644
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001645 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001646 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001647 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001648 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001649 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001650 else if (sc->fmt->errpid) {
1651 struct thread *child = machine__find_thread(trace->host, ret, ret);
1652
1653 if (child != NULL) {
1654 fprintf(trace->output, ") = %ld", ret);
1655 if (child->comm_set)
1656 fprintf(trace->output, " (%s)", thread__comm_str(child));
1657 thread__put(child);
1658 }
1659 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001660 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001661
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001662 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001663
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001664 if (callchain_ret > 0)
1665 trace__fprintf_callchain(trace, sample);
1666 else if (callchain_ret < 0)
1667 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001668out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001670 err = 0;
1671out_put:
1672 thread__put(thread);
1673 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001674}
1675
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001676static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001677 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001678 struct perf_sample *sample)
1679{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001680 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1681 struct thread_trace *ttrace;
1682 size_t filename_len, entry_str_len, to_move;
1683 ssize_t remaining_space;
1684 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001685 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001686
1687 if (!thread)
1688 goto out;
1689
1690 ttrace = thread__priv(thread);
1691 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001692 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001693
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001694 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001695 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001696 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001697
1698 if (ttrace->filename.namelen < filename_len) {
1699 char *f = realloc(ttrace->filename.name, filename_len + 1);
1700
1701 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001702 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001703
1704 ttrace->filename.namelen = filename_len;
1705 ttrace->filename.name = f;
1706 }
1707
1708 strcpy(ttrace->filename.name, filename);
1709 ttrace->filename.pending_open = true;
1710
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001711 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001712 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001713
1714 entry_str_len = strlen(ttrace->entry_str);
1715 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1716 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001717 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001718
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001719 if (filename_len > (size_t)remaining_space) {
1720 filename += filename_len - remaining_space;
1721 filename_len = remaining_space;
1722 }
1723
1724 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1725 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1726 memmove(pos + filename_len, pos, to_move);
1727 memcpy(pos, filename, filename_len);
1728
1729 ttrace->filename.ptr = 0;
1730 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001731out_put:
1732 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001733out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001734 return 0;
1735}
1736
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001737static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001738 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001739 struct perf_sample *sample)
1740{
1741 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1742 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001743 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001744 sample->pid,
1745 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001746 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001747
1748 if (ttrace == NULL)
1749 goto out_dump;
1750
1751 ttrace->runtime_ms += runtime_ms;
1752 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001753out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001754 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001755 return 0;
1756
1757out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001758 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001759 evsel->name,
1760 perf_evsel__strval(evsel, sample, "comm"),
1761 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1762 runtime,
1763 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001764 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001765}
1766
Wang Nan1d6c9402016-02-26 09:31:55 +00001767static void bpf_output__printer(enum binary_printer_ops op,
1768 unsigned int val, void *extra)
1769{
1770 FILE *output = extra;
1771 unsigned char ch = (unsigned char)val;
1772
1773 switch (op) {
1774 case BINARY_PRINT_CHAR_DATA:
1775 fprintf(output, "%c", isprint(ch) ? ch : '.');
1776 break;
1777 case BINARY_PRINT_DATA_BEGIN:
1778 case BINARY_PRINT_LINE_BEGIN:
1779 case BINARY_PRINT_ADDR:
1780 case BINARY_PRINT_NUM_DATA:
1781 case BINARY_PRINT_NUM_PAD:
1782 case BINARY_PRINT_SEP:
1783 case BINARY_PRINT_CHAR_PAD:
1784 case BINARY_PRINT_LINE_END:
1785 case BINARY_PRINT_DATA_END:
1786 default:
1787 break;
1788 }
1789}
1790
1791static void bpf_output__fprintf(struct trace *trace,
1792 struct perf_sample *sample)
1793{
1794 print_binary(sample->raw_data, sample->raw_size, 8,
1795 bpf_output__printer, trace->output);
1796}
1797
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001798static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1799 union perf_event *event __maybe_unused,
1800 struct perf_sample *sample)
1801{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001802 int callchain_ret = 0;
1803
1804 if (sample->callchain) {
1805 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1806 if (callchain_ret == 0) {
1807 if (callchain_cursor.nr < trace->min_stack)
1808 goto out;
1809 callchain_ret = 1;
1810 }
1811 }
1812
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001813 trace__printf_interrupted_entry(trace, sample);
1814 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001815
1816 if (trace->trace_syscalls)
1817 fprintf(trace->output, "( ): ");
1818
1819 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001820
Wang Nan1d6c9402016-02-26 09:31:55 +00001821 if (perf_evsel__is_bpf_output(evsel)) {
1822 bpf_output__fprintf(trace, sample);
1823 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001824 event_format__fprintf(evsel->tp_format, sample->cpu,
1825 sample->raw_data, sample->raw_size,
1826 trace->output);
1827 }
1828
1829 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001830
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001831 if (callchain_ret > 0)
1832 trace__fprintf_callchain(trace, sample);
1833 else if (callchain_ret < 0)
1834 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1835out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001836 return 0;
1837}
1838
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001839static void print_location(FILE *f, struct perf_sample *sample,
1840 struct addr_location *al,
1841 bool print_dso, bool print_sym)
1842{
1843
Namhyung Kimbb963e12017-02-17 17:17:38 +09001844 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001845 fprintf(f, "%s@", al->map->dso->long_name);
1846
Namhyung Kimbb963e12017-02-17 17:17:38 +09001847 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001848 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001849 al->addr - al->sym->start);
1850 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001851 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001852 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001853 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001854}
1855
1856static int trace__pgfault(struct trace *trace,
1857 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001858 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001859 struct perf_sample *sample)
1860{
1861 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001862 struct addr_location al;
1863 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001864 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001865 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001866 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001867
1868 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001869
1870 if (sample->callchain) {
1871 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1872 if (callchain_ret == 0) {
1873 if (callchain_cursor.nr < trace->min_stack)
1874 goto out_put;
1875 callchain_ret = 1;
1876 }
1877 }
1878
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001879 ttrace = thread__trace(thread, trace->output);
1880 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001881 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001882
1883 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1884 ttrace->pfmaj++;
1885 else
1886 ttrace->pfmin++;
1887
1888 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001889 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001890
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001891 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001892 sample->ip, &al);
1893
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001894 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001895
1896 fprintf(trace->output, "%sfault [",
1897 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1898 "maj" : "min");
1899
1900 print_location(trace->output, sample, &al, false, true);
1901
1902 fprintf(trace->output, "] => ");
1903
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001904 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001905 sample->addr, &al);
1906
1907 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001908 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001909 MAP__FUNCTION, sample->addr, &al);
1910
1911 if (al.map)
1912 map_type = 'x';
1913 else
1914 map_type = '?';
1915 }
1916
1917 print_location(trace->output, sample, &al, true, false);
1918
1919 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001920
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001921 if (callchain_ret > 0)
1922 trace__fprintf_callchain(trace, sample);
1923 else if (callchain_ret < 0)
1924 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001925out:
1926 err = 0;
1927out_put:
1928 thread__put(thread);
1929 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001930}
1931
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001932static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001933 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001934 struct perf_sample *sample)
1935{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001936 /*
1937 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1938 * and don't use sample->time unconditionally, we may end up having
1939 * some other event in the future without PERF_SAMPLE_TIME for good
1940 * reason, i.e. we may not be interested in its timestamps, just in
1941 * it taking place, picking some piece of information when it
1942 * appears in our event stream (vfs_getname comes to mind).
1943 */
1944 if (trace->base_time == 0 && !trace->full_time &&
1945 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001946 trace->base_time = sample->time;
1947}
1948
David Ahern6810fc92013-08-28 22:29:52 -06001949static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001950 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001951 struct perf_sample *sample,
1952 struct perf_evsel *evsel,
1953 struct machine *machine __maybe_unused)
1954{
1955 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001956 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001957 int err = 0;
1958
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001959 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001960
David Ahernaa07df62016-11-25 09:29:52 -07001961 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1962 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001963 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06001964
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001965 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001966
David Ahern31605652013-12-04 19:41:41 -07001967 if (handler) {
1968 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001969 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001970 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001971out:
1972 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06001973 return err;
1974}
1975
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001976static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06001977{
1978 unsigned int rec_argc, i, j;
1979 const char **rec_argv;
1980 const char * const record_args[] = {
1981 "record",
1982 "-R",
1983 "-m", "1024",
1984 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06001985 };
1986
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001987 const char * const sc_args[] = { "-e", };
1988 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
1989 const char * const majpf_args[] = { "-e", "major-faults" };
1990 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
1991 const char * const minpf_args[] = { "-e", "minor-faults" };
1992 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
1993
David Ahern9aca7f12013-12-04 19:41:39 -07001994 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04001995 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
1996 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06001997 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1998
1999 if (rec_argv == NULL)
2000 return -ENOMEM;
2001
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002002 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002003 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002004 rec_argv[j++] = record_args[i];
2005
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002006 if (trace->trace_syscalls) {
2007 for (i = 0; i < sc_args_nr; i++)
2008 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002009
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002010 /* event string may be different for older kernels - e.g., RHEL6 */
2011 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2012 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2013 else if (is_valid_tracepoint("syscalls:sys_enter"))
2014 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2015 else {
2016 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2017 return -1;
2018 }
David Ahern9aca7f12013-12-04 19:41:39 -07002019 }
David Ahern9aca7f12013-12-04 19:41:39 -07002020
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002021 if (trace->trace_pgfaults & TRACE_PFMAJ)
2022 for (i = 0; i < majpf_args_nr; i++)
2023 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002024
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002025 if (trace->trace_pgfaults & TRACE_PFMIN)
2026 for (i = 0; i < minpf_args_nr; i++)
2027 rec_argv[j++] = minpf_args[i];
2028
2029 for (i = 0; i < (unsigned int)argc; i++)
2030 rec_argv[j++] = argv[i];
2031
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002032 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002033}
2034
David Ahernbf2575c2013-10-08 21:26:53 -06002035static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2036
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002037static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002038{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002039 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002040
2041 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002042 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002043
2044 if (perf_evsel__field(evsel, "pathname") == NULL) {
2045 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002046 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002047 }
2048
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002049 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002050 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002051 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002052}
2053
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002054static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002055{
2056 struct perf_evsel *evsel;
2057 struct perf_event_attr attr = {
2058 .type = PERF_TYPE_SOFTWARE,
2059 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002060 };
2061
2062 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002063 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002064
2065 event_attr_init(&attr);
2066
2067 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002068 if (evsel)
2069 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002070
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002071 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002072}
2073
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002074static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2075{
2076 const u32 type = event->header.type;
2077 struct perf_evsel *evsel;
2078
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002079 if (type != PERF_RECORD_SAMPLE) {
2080 trace__process_event(trace, trace->host, event, sample);
2081 return;
2082 }
2083
2084 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2085 if (evsel == NULL) {
2086 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2087 return;
2088 }
2089
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002090 trace__set_base_time(trace, evsel, sample);
2091
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002092 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2093 sample->raw_data == NULL) {
2094 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2095 perf_evsel__name(evsel), sample->tid,
2096 sample->cpu, sample->raw_size);
2097 } else {
2098 tracepoint_handler handler = evsel->handler;
2099 handler(trace, evsel, event, sample);
2100 }
2101}
2102
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002103static int trace__add_syscall_newtp(struct trace *trace)
2104{
2105 int ret = -1;
2106 struct perf_evlist *evlist = trace->evlist;
2107 struct perf_evsel *sys_enter, *sys_exit;
2108
2109 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2110 if (sys_enter == NULL)
2111 goto out;
2112
2113 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2114 goto out_delete_sys_enter;
2115
2116 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2117 if (sys_exit == NULL)
2118 goto out_delete_sys_enter;
2119
2120 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2121 goto out_delete_sys_exit;
2122
2123 perf_evlist__add(evlist, sys_enter);
2124 perf_evlist__add(evlist, sys_exit);
2125
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002126 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002127 /*
2128 * We're interested only in the user space callchain
2129 * leading to the syscall, allow overriding that for
2130 * debugging reasons using --kernel_syscall_callchains
2131 */
2132 sys_exit->attr.exclude_callchain_kernel = 1;
2133 }
2134
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002135 trace->syscalls.events.sys_enter = sys_enter;
2136 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002137
2138 ret = 0;
2139out:
2140 return ret;
2141
2142out_delete_sys_exit:
2143 perf_evsel__delete_priv(sys_exit);
2144out_delete_sys_enter:
2145 perf_evsel__delete_priv(sys_enter);
2146 goto out;
2147}
2148
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002149static int trace__set_ev_qualifier_filter(struct trace *trace)
2150{
2151 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002152 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002153 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2154 trace->ev_qualifier_ids.nr,
2155 trace->ev_qualifier_ids.entries);
2156
2157 if (filter == NULL)
2158 goto out_enomem;
2159
Mathieu Poirier3541c032016-09-16 08:44:04 -06002160 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2161 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002162 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002163 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002164 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002165
2166 free(filter);
2167out:
2168 return err;
2169out_enomem:
2170 errno = ENOMEM;
2171 goto out;
2172}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002173
Namhyung Kimf15eb532012-10-05 14:02:16 +09002174static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002175{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002176 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002177 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002178 int err = -1, i;
2179 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002180 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002181 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002182
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002183 trace->live = true;
2184
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002185 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002186 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002187
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002188 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002189 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002190
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002191 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2192 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2193 if (pgfault_maj == NULL)
2194 goto out_error_mem;
2195 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002196 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002197
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002198 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2199 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2200 if (pgfault_min == NULL)
2201 goto out_error_mem;
2202 perf_evlist__add(evlist, pgfault_min);
2203 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002204
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002205 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002206 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2207 trace__sched_stat_runtime))
2208 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002209
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002210 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2211 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002212 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002213 goto out_delete_evlist;
2214 }
2215
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002216 err = trace__symbols_init(trace, evlist);
2217 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002218 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002219 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002220 }
2221
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002222 perf_evlist__config(evlist, &trace->opts, NULL);
2223
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002224 if (callchain_param.enabled) {
2225 bool use_identifier = false;
2226
2227 if (trace->syscalls.events.sys_exit) {
2228 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2229 &trace->opts, &callchain_param);
2230 use_identifier = true;
2231 }
2232
2233 if (pgfault_maj) {
2234 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2235 use_identifier = true;
2236 }
2237
2238 if (pgfault_min) {
2239 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2240 use_identifier = true;
2241 }
2242
2243 if (use_identifier) {
2244 /*
2245 * Now we have evsels with different sample_ids, use
2246 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2247 * from a fixed position in each ring buffer record.
2248 *
2249 * As of this the changeset introducing this comment, this
2250 * isn't strictly needed, as the fields that can come before
2251 * PERF_SAMPLE_ID are all used, but we'll probably disable
2252 * some of those for things like copying the payload of
2253 * pointer syscall arguments, and for vfs_getname we don't
2254 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2255 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2256 */
2257 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2258 perf_evlist__reset_sample_bit(evlist, ID);
2259 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002260 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261
Namhyung Kimf15eb532012-10-05 14:02:16 +09002262 signal(SIGCHLD, sig_handler);
2263 signal(SIGINT, sig_handler);
2264
2265 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002266 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002267 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002268 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002269 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002270 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002271 }
2272 }
2273
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002274 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002275 if (err < 0)
2276 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002277
Wang Nanba504232016-02-26 09:31:54 +00002278 err = bpf__apply_obj_config();
2279 if (err) {
2280 char errbuf[BUFSIZ];
2281
2282 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2283 pr_err("ERROR: Apply config to BPF failed: %s\n",
2284 errbuf);
2285 goto out_error_open;
2286 }
2287
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002288 /*
2289 * Better not use !target__has_task() here because we need to cover the
2290 * case where no threads were specified in the command line, but a
2291 * workload was, and in that case we will fill in the thread_map when
2292 * we fork the workload in perf_evlist__prepare_workload.
2293 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002294 if (trace->filter_pids.nr > 0)
2295 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002296 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002297 err = perf_evlist__set_filter_pid(evlist, getpid());
2298
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002299 if (err < 0)
2300 goto out_error_mem;
2301
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002302 if (trace->ev_qualifier_ids.nr > 0) {
2303 err = trace__set_ev_qualifier_filter(trace);
2304 if (err < 0)
2305 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002306
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002307 pr_debug("event qualifier tracepoint filter: %s\n",
2308 trace->syscalls.events.sys_exit->filter);
2309 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002310
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002311 err = perf_evlist__apply_filters(evlist, &evsel);
2312 if (err < 0)
2313 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002314
Jiri Olsaf8850372013-11-28 17:57:22 +01002315 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002316 if (err < 0)
2317 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002318
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002319 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002320 perf_evlist__enable(evlist);
2321
Namhyung Kimf15eb532012-10-05 14:02:16 +09002322 if (forks)
2323 perf_evlist__start_workload(evlist);
2324
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002325 if (trace->opts.initial_delay) {
2326 usleep(trace->opts.initial_delay * 1000);
2327 perf_evlist__enable(evlist);
2328 }
2329
Jiri Olsae13798c2015-06-23 00:36:02 +02002330 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002331 evlist->threads->nr > 1 ||
2332 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002334 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002335
2336 for (i = 0; i < evlist->nr_mmaps; i++) {
2337 union perf_event *event;
2338
2339 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002340 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002341
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002342 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002343
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002344 err = perf_evlist__parse_sample(evlist, event, &sample);
2345 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002346 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002347 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002348 }
2349
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002350 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002351next_event:
2352 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002353
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002354 if (interrupted)
2355 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002356
2357 if (done && !draining) {
2358 perf_evlist__disable(evlist);
2359 draining = true;
2360 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002361 }
2362 }
2363
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002364 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002365 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002366
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002367 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2368 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2369 draining = true;
2370
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002371 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002372 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002373 } else {
2374 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002375 }
2376
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002377out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002378 thread__zput(trace->current);
2379
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002380 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002381
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002382 if (!err) {
2383 if (trace->summary)
2384 trace__fprintf_thread_summary(trace, trace->output);
2385
2386 if (trace->show_tool_stats) {
2387 fprintf(trace->output, "Stats:\n "
2388 " vfs_getname : %" PRIu64 "\n"
2389 " proc_getname: %" PRIu64 "\n",
2390 trace->stats.vfs_getname,
2391 trace->stats.proc_getname);
2392 }
2393 }
David Ahernbf2575c2013-10-08 21:26:53 -06002394
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002395out_delete_evlist:
2396 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002397 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002398 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002399 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002400{
2401 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002402
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002403out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002404 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002405 goto out_error;
2406
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002407out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002408 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002409 goto out_error;
2410
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002411out_error_mmap:
2412 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2413 goto out_error;
2414
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002415out_error_open:
2416 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2417
2418out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002419 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302420 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002421
2422out_error_apply_filters:
2423 fprintf(trace->output,
2424 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2425 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002426 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002427 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002428}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002429out_error_mem:
2430 fprintf(trace->output, "Not enough memory to run!\n");
2431 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002432
2433out_errno:
2434 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2435 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002436}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002437
David Ahern6810fc92013-08-28 22:29:52 -06002438static int trace__replay(struct trace *trace)
2439{
2440 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002441 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002442 };
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002443 struct perf_data_file file = {
2444 .path = input_name,
2445 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002446 .force = trace->force,
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002447 };
David Ahern6810fc92013-08-28 22:29:52 -06002448 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002449 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002450 int err = -1;
2451
2452 trace->tool.sample = trace__process_sample;
2453 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002454 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002455 trace->tool.comm = perf_event__process_comm;
2456 trace->tool.exit = perf_event__process_exit;
2457 trace->tool.fork = perf_event__process_fork;
2458 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302459 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002460 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302461 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002462
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002463 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002464 trace->tool.ordering_requires_timestamps = true;
2465
2466 /* add tid to output */
2467 trace->multiple_threads = true;
2468
Jiri Olsaf5fc1412013-10-15 16:27:32 +02002469 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002470 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002471 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002472
David Ahernaa07df62016-11-25 09:29:52 -07002473 if (trace->opts.target.pid)
2474 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2475
2476 if (trace->opts.target.tid)
2477 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2478
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002479 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002480 goto out;
2481
David Ahern8fb598e2013-09-28 13:13:00 -06002482 trace->host = &session->machines.host;
2483
David Ahern6810fc92013-08-28 22:29:52 -06002484 err = perf_session__set_tracepoints_handlers(session, handlers);
2485 if (err)
2486 goto out;
2487
Namhyung Kim003824e2013-11-12 15:25:00 +09002488 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2489 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002490 /* older kernels have syscalls tp versus raw_syscalls */
2491 if (evsel == NULL)
2492 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2493 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002494
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002495 if (evsel &&
2496 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2497 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002498 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2499 goto out;
2500 }
2501
2502 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2503 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002504 if (evsel == NULL)
2505 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2506 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002507 if (evsel &&
2508 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2509 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002510 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002511 goto out;
2512 }
2513
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002514 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002515 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2516 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2517 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2518 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2519 evsel->handler = trace__pgfault;
2520 }
2521
David Ahern6810fc92013-08-28 22:29:52 -06002522 setup_pager();
2523
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002524 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002525 if (err)
2526 pr_err("Failed to process events, error %d", err);
2527
David Ahernbf2575c2013-10-08 21:26:53 -06002528 else if (trace->summary)
2529 trace__fprintf_thread_summary(trace, trace->output);
2530
David Ahern6810fc92013-08-28 22:29:52 -06002531out:
2532 perf_session__delete(session);
2533
2534 return err;
2535}
2536
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002537static size_t trace__fprintf_threads_header(FILE *fp)
2538{
2539 size_t printed;
2540
Pekka Enberg99ff7152013-11-12 16:42:14 +02002541 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002542
2543 return printed;
2544}
2545
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002546DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2547 struct stats *stats;
2548 double msecs;
2549 int syscall;
2550)
2551{
2552 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2553 struct stats *stats = source->priv;
2554
2555 entry->syscall = source->i;
2556 entry->stats = stats;
2557 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2558}
2559
David Ahernbf2575c2013-10-08 21:26:53 -06002560static size_t thread__dump_stats(struct thread_trace *ttrace,
2561 struct trace *trace, FILE *fp)
2562{
David Ahernbf2575c2013-10-08 21:26:53 -06002563 size_t printed = 0;
2564 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002565 struct rb_node *nd;
2566 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002567
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002568 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002569 return 0;
2570
2571 printed += fprintf(fp, "\n");
2572
Milian Wolff834fd462015-08-06 11:24:29 +02002573 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2574 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2575 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002576
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002577 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002578 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002579 if (stats) {
2580 double min = (double)(stats->min) / NSEC_PER_MSEC;
2581 double max = (double)(stats->max) / NSEC_PER_MSEC;
2582 double avg = avg_stats(stats);
2583 double pct;
2584 u64 n = (u64) stats->n;
2585
2586 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2587 avg /= NSEC_PER_MSEC;
2588
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002589 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002590 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002591 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002592 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002593 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002594 }
David Ahernbf2575c2013-10-08 21:26:53 -06002595 }
2596
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002597 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002598 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002599
2600 return printed;
2601}
2602
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002603static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002604{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002605 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002606 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002607 double ratio;
2608
2609 if (ttrace == NULL)
2610 return 0;
2611
2612 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2613
Pekka Enberg15e65c62013-11-14 18:43:30 +02002614 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002615 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002616 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002617 if (ttrace->pfmaj)
2618 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2619 if (ttrace->pfmin)
2620 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002621 if (trace->sched)
2622 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2623 else if (fputc('\n', fp) != EOF)
2624 ++printed;
2625
David Ahernbf2575c2013-10-08 21:26:53 -06002626 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002627
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002628 return printed;
2629}
David Ahern896cbb52013-09-28 13:12:59 -06002630
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002631static unsigned long thread__nr_events(struct thread_trace *ttrace)
2632{
2633 return ttrace ? ttrace->nr_events : 0;
2634}
2635
2636DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2637 struct thread *thread;
2638)
2639{
2640 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002641}
2642
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002643static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2644{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002645 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2646 size_t printed = trace__fprintf_threads_header(fp);
2647 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002648
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002649 if (threads == NULL) {
2650 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2651 return 0;
2652 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002653
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002654 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002655 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2656
2657 resort_rb__delete(threads);
2658
2659 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002660}
2661
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002662static int trace__set_duration(const struct option *opt, const char *str,
2663 int unset __maybe_unused)
2664{
2665 struct trace *trace = opt->value;
2666
2667 trace->duration_filter = atof(str);
2668 return 0;
2669}
2670
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002671static int trace__set_filter_pids(const struct option *opt, const char *str,
2672 int unset __maybe_unused)
2673{
2674 int ret = -1;
2675 size_t i;
2676 struct trace *trace = opt->value;
2677 /*
2678 * FIXME: introduce a intarray class, plain parse csv and create a
2679 * { int nr, int entries[] } struct...
2680 */
2681 struct intlist *list = intlist__new(str);
2682
2683 if (list == NULL)
2684 return -1;
2685
2686 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2687 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2688
2689 if (trace->filter_pids.entries == NULL)
2690 goto out;
2691
2692 trace->filter_pids.entries[0] = getpid();
2693
2694 for (i = 1; i < trace->filter_pids.nr; ++i)
2695 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2696
2697 intlist__delete(list);
2698 ret = 0;
2699out:
2700 return ret;
2701}
2702
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002703static int trace__open_output(struct trace *trace, const char *filename)
2704{
2705 struct stat st;
2706
2707 if (!stat(filename, &st) && st.st_size) {
2708 char oldname[PATH_MAX];
2709
2710 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2711 unlink(oldname);
2712 rename(filename, oldname);
2713 }
2714
2715 trace->output = fopen(filename, "w");
2716
2717 return trace->output == NULL ? -errno : 0;
2718}
2719
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002720static int parse_pagefaults(const struct option *opt, const char *str,
2721 int unset __maybe_unused)
2722{
2723 int *trace_pgfaults = opt->value;
2724
2725 if (strcmp(str, "all") == 0)
2726 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2727 else if (strcmp(str, "maj") == 0)
2728 *trace_pgfaults |= TRACE_PFMAJ;
2729 else if (strcmp(str, "min") == 0)
2730 *trace_pgfaults |= TRACE_PFMIN;
2731 else
2732 return -1;
2733
2734 return 0;
2735}
2736
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002737static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2738{
2739 struct perf_evsel *evsel;
2740
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002741 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002742 evsel->handler = handler;
2743}
2744
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002745/*
2746 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2747 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2748 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2749 *
2750 * It'd be better to introduce a parse_options() variant that would return a
2751 * list with the terms it didn't match to an event...
2752 */
2753static int trace__parse_events_option(const struct option *opt, const char *str,
2754 int unset __maybe_unused)
2755{
2756 struct trace *trace = (struct trace *)opt->value;
2757 const char *s = str;
2758 char *sep = NULL, *lists[2] = { NULL, NULL, };
2759 int len = strlen(str), err = -1, list;
2760 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2761 char group_name[PATH_MAX];
2762
2763 if (strace_groups_dir == NULL)
2764 return -1;
2765
2766 if (*s == '!') {
2767 ++s;
2768 trace->not_ev_qualifier = true;
2769 }
2770
2771 while (1) {
2772 if ((sep = strchr(s, ',')) != NULL)
2773 *sep = '\0';
2774
2775 list = 0;
2776 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2777 list = 1;
2778 } else {
2779 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2780 if (access(group_name, R_OK) == 0)
2781 list = 1;
2782 }
2783
2784 if (lists[list]) {
2785 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2786 } else {
2787 lists[list] = malloc(len);
2788 if (lists[list] == NULL)
2789 goto out;
2790 strcpy(lists[list], s);
2791 }
2792
2793 if (!sep)
2794 break;
2795
2796 *sep = ',';
2797 s = sep + 1;
2798 }
2799
2800 if (lists[1] != NULL) {
2801 struct strlist_config slist_config = {
2802 .dirname = strace_groups_dir,
2803 };
2804
2805 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2806 if (trace->ev_qualifier == NULL) {
2807 fputs("Not enough memory to parse event qualifier", trace->output);
2808 goto out;
2809 }
2810
2811 if (trace__validate_ev_qualifier(trace))
2812 goto out;
2813 }
2814
2815 err = 0;
2816
2817 if (lists[0]) {
2818 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2819 "event selector. use 'perf list' to list available events",
2820 parse_events_option);
2821 err = parse_events_option(&o, lists[0], 0);
2822 }
2823out:
2824 if (sep)
2825 *sep = ',';
2826
2827 return err;
2828}
2829
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002830int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002831{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002832 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002833 "perf trace [<options>] [<command>]",
2834 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002835 "perf trace record [<options>] [<command>]",
2836 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002837 NULL
2838 };
2839 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002840 .syscalls = {
2841 . max = -1,
2842 },
2843 .opts = {
2844 .target = {
2845 .uid = UINT_MAX,
2846 .uses_mmap = true,
2847 },
2848 .user_freq = UINT_MAX,
2849 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002850 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002851 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002852 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002853 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002854 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002855 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002856 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002857 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002858 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002859 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002860 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002861 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002862 OPT_CALLBACK('e', "event", &trace, "event",
2863 "event/syscall selector. use 'perf list' to list available events",
2864 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002865 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2866 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002867 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002868 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2869 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002870 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002871 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002872 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2873 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002874 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002875 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002876 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2877 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002878 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002879 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002880 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002881 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002882 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002883 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002884 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2885 "number of mmap data pages",
2886 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002887 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002888 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002889 OPT_CALLBACK(0, "duration", &trace, "float",
2890 "show only events with duration > N.M ms",
2891 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002892 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002893 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002894 OPT_BOOLEAN('T', "time", &trace.full_time,
2895 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002896 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2897 "Show only syscall summary with statistics"),
2898 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2899 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002900 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2901 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002902 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002903 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002904 OPT_CALLBACK(0, "call-graph", &trace.opts,
2905 "record_mode[,record_size]", record_callchain_help,
2906 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002907 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2908 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002909 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2910 "Set the minimum stack depth when parsing the callchain, "
2911 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002912 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2913 "Set the maximum stack depth when parsing the callchain, "
2914 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002915 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002916 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2917 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002918 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2919 "ms to wait before starting measurement after program "
2920 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002921 OPT_END()
2922 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002923 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002924 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002925 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002926 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002927 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002928
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002929 signal(SIGSEGV, sighandler_dump_stack);
2930 signal(SIGFPE, sighandler_dump_stack);
2931
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002932 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002933 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002934
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002935 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002936 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002937 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002938 goto out;
2939 }
2940
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002941 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2942 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002943
Wang Nand7888572016-04-08 15:07:24 +00002944 err = bpf__setup_stdout(trace.evlist);
2945 if (err) {
2946 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2947 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2948 goto out;
2949 }
2950
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002951 err = -1;
2952
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002953 if (trace.trace_pgfaults) {
2954 trace.opts.sample_address = true;
2955 trace.opts.sample_time = true;
2956 }
2957
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002958 if (trace.opts.mmap_pages == UINT_MAX)
2959 mmap_pages_user_set = false;
2960
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002961 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002962 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002963 max_stack_user_set = false;
2964 }
2965
2966#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03002967 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002968 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
2969#endif
2970
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002971 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002972 if (!mmap_pages_user_set && geteuid() == 0)
2973 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
2974
Milian Wolff566a0882016-04-08 13:34:15 +02002975 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002976 }
Milian Wolff566a0882016-04-08 13:34:15 +02002977
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002978 if (trace.evlist->nr_entries > 0)
2979 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2980
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002981 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2982 return trace__record(&trace, argc-1, &argv[1]);
2983
2984 /* summary_only implies summary option, but don't overwrite summary if set */
2985 if (trace.summary_only)
2986 trace.summary = trace.summary_only;
2987
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01002988 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2989 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002990 pr_err("Please specify something to trace.\n");
2991 return -1;
2992 }
2993
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002994 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002995 pr_err("The -e option can't be used with --no-syscalls.\n");
2996 goto out;
2997 }
2998
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002999 if (output_name != NULL) {
3000 err = trace__open_output(&trace, output_name);
3001 if (err < 0) {
3002 perror("failed to create output file");
3003 goto out;
3004 }
3005 }
3006
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003007 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3008
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003009 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003010 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;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003014 }
3015
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003016 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003017 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003018 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003019 fprintf(trace.output, "%s", bf);
3020 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003021 }
3022
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003023 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003024 trace.opts.target.system_wide = true;
3025
David Ahern6810fc92013-08-28 22:29:52 -06003026 if (input_name)
3027 err = trace__replay(&trace);
3028 else
3029 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003030
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003031out_close:
3032 if (output_name != NULL)
3033 fclose(trace.output);
3034out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003035 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003036}