blob: de02413a25d3cbcd420171bc31f08ee977df414a [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 Melo83a51692017-07-13 17:14:11 -030067#ifndef F_LINUX_SPECIFIC_BASE
68# define F_LINUX_SPECIFIC_BASE 1024
69#endif
70
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030071struct trace {
72 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030073 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030074 struct {
75 int max;
76 struct syscall *table;
77 struct {
78 struct perf_evsel *sys_enter,
79 *sys_exit;
80 } events;
81 } syscalls;
82 struct record_opts opts;
83 struct perf_evlist *evlist;
84 struct machine *host;
85 struct thread *current;
86 u64 base_time;
87 FILE *output;
88 unsigned long nr_events;
89 struct strlist *ev_qualifier;
90 struct {
91 size_t nr;
92 int *entries;
93 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030094 struct {
95 size_t nr;
96 pid_t *entries;
97 } filter_pids;
98 double duration_filter;
99 double runtime_ms;
100 struct {
101 u64 vfs_getname,
102 proc_getname;
103 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300104 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300105 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106 bool not_ev_qualifier;
107 bool live;
108 bool full_time;
109 bool sched;
110 bool multiple_threads;
111 bool summary;
112 bool summary_only;
113 bool show_comm;
114 bool show_tool_stats;
115 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300116 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117 bool force;
118 bool vfs_getname;
119 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300120 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300122
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300123struct tp_field {
124 int offset;
125 union {
126 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
127 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
128 };
129};
130
131#define TP_UINT_FIELD(bits) \
132static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
133{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500134 u##bits value; \
135 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
136 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300137}
138
139TP_UINT_FIELD(8);
140TP_UINT_FIELD(16);
141TP_UINT_FIELD(32);
142TP_UINT_FIELD(64);
143
144#define TP_UINT_FIELD__SWAPPED(bits) \
145static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
146{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500147 u##bits value; \
148 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300149 return bswap_##bits(value);\
150}
151
152TP_UINT_FIELD__SWAPPED(16);
153TP_UINT_FIELD__SWAPPED(32);
154TP_UINT_FIELD__SWAPPED(64);
155
156static int tp_field__init_uint(struct tp_field *field,
157 struct format_field *format_field,
158 bool needs_swap)
159{
160 field->offset = format_field->offset;
161
162 switch (format_field->size) {
163 case 1:
164 field->integer = tp_field__u8;
165 break;
166 case 2:
167 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
168 break;
169 case 4:
170 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
171 break;
172 case 8:
173 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
174 break;
175 default:
176 return -1;
177 }
178
179 return 0;
180}
181
182static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
183{
184 return sample->raw_data + field->offset;
185}
186
187static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
188{
189 field->offset = format_field->offset;
190 field->pointer = tp_field__ptr;
191 return 0;
192}
193
194struct syscall_tp {
195 struct tp_field id;
196 union {
197 struct tp_field args, ret;
198 };
199};
200
201static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
202 struct tp_field *field,
203 const char *name)
204{
205 struct format_field *format_field = perf_evsel__field(evsel, name);
206
207 if (format_field == NULL)
208 return -1;
209
210 return tp_field__init_uint(field, format_field, evsel->needs_swap);
211}
212
213#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
214 ({ struct syscall_tp *sc = evsel->priv;\
215 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
216
217static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
218 struct tp_field *field,
219 const char *name)
220{
221 struct format_field *format_field = perf_evsel__field(evsel, name);
222
223 if (format_field == NULL)
224 return -1;
225
226 return tp_field__init_ptr(field, format_field);
227}
228
229#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
230 ({ struct syscall_tp *sc = evsel->priv;\
231 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
232
233static void perf_evsel__delete_priv(struct perf_evsel *evsel)
234{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300235 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300236 perf_evsel__delete(evsel);
237}
238
Namhyung Kim96695d42013-11-12 08:51:45 -0300239static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
240{
241 evsel->priv = malloc(sizeof(struct syscall_tp));
242 if (evsel->priv != NULL) {
243 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
244 goto out_delete;
245
246 evsel->handler = handler;
247 return 0;
248 }
249
250 return -ENOMEM;
251
252out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300253 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300254 return -ENOENT;
255}
256
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300257static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300258{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300259 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300260
David Ahern9aca7f12013-12-04 19:41:39 -0700261 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200262 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700263 evsel = perf_evsel__newtp("syscalls", direction);
264
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200265 if (IS_ERR(evsel))
266 return NULL;
267
268 if (perf_evsel__init_syscall_tp(evsel, handler))
269 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300270
271 return evsel;
272
273out_delete:
274 perf_evsel__delete_priv(evsel);
275 return NULL;
276}
277
278#define perf_evsel__sc_tp_uint(evsel, name, sample) \
279 ({ struct syscall_tp *fields = evsel->priv; \
280 fields->name.integer(&fields->name, sample); })
281
282#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
283 ({ struct syscall_tp *fields = evsel->priv; \
284 fields->name.pointer(&fields->name, sample); })
285
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300286size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
287{
288 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300289
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300290 if (idx < 0 || idx >= sa->nr_entries)
291 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300292
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300293 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300300 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301}
302
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
307}
308
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309#define SCA_STRARRAY syscall_arg__scnprintf_strarray
310
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300311struct strarrays {
312 int nr_entries;
313 struct strarray **entries;
314};
315
316#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
317 .nr_entries = ARRAY_SIZE(array), \
318 .entries = array, \
319}
320
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300321size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
322 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300323{
324 struct strarrays *sas = arg->parm;
325 int i;
326
327 for (i = 0; i < sas->nr_entries; ++i) {
328 struct strarray *sa = sas->entries[i];
329 int idx = arg->val - sa->offset;
330
331 if (idx >= 0 && idx < sa->nr_entries) {
332 if (sa->entries[idx] == NULL)
333 break;
334 return scnprintf(bf, size, "%s", sa->entries[idx]);
335 }
336 }
337
338 return scnprintf(bf, size, "%d", arg->val);
339}
340
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300341#ifndef AT_FDCWD
342#define AT_FDCWD -100
343#endif
344
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300345static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
346 struct syscall_arg *arg)
347{
348 int fd = arg->val;
349
350 if (fd == AT_FDCWD)
351 return scnprintf(bf, size, "CWD");
352
353 return syscall_arg__scnprintf_fd(bf, size, arg);
354}
355
356#define SCA_FDAT syscall_arg__scnprintf_fd_at
357
358static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
359 struct syscall_arg *arg);
360
361#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
362
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300363size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300364{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300365 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300366}
367
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300368size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300369{
370 return scnprintf(bf, size, "%d", arg->val);
371}
372
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300373size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
374{
375 return scnprintf(bf, size, "%ld", arg->val);
376}
377
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300378static const char *bpf_cmd[] = {
379 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
380 "MAP_GET_NEXT_KEY", "PROG_LOAD",
381};
382static DEFINE_STRARRAY(bpf_cmd);
383
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300384static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
385static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300386
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300387static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
388static DEFINE_STRARRAY(itimers);
389
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300390static const char *keyctl_options[] = {
391 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
392 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
393 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
394 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
395 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
396};
397static DEFINE_STRARRAY(keyctl_options);
398
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300399static const char *whences[] = { "SET", "CUR", "END",
400#ifdef SEEK_DATA
401"DATA",
402#endif
403#ifdef SEEK_HOLE
404"HOLE",
405#endif
406};
407static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300408
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300409static const char *fcntl_cmds[] = {
410 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300411 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
412 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
413 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300414};
415static DEFINE_STRARRAY(fcntl_cmds);
416
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300417static const char *fcntl_linux_specific_cmds[] = {
418 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
419 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300420 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300421};
422
423static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
424
425static struct strarray *fcntl_cmds_arrays[] = {
426 &strarray__fcntl_cmds,
427 &strarray__fcntl_linux_specific_cmds,
428};
429
430static DEFINE_STRARRAYS(fcntl_cmds_arrays);
431
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300432static const char *rlimit_resources[] = {
433 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
434 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
435 "RTTIME",
436};
437static DEFINE_STRARRAY(rlimit_resources);
438
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300439static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
440static DEFINE_STRARRAY(sighow);
441
David Ahern4f8c1b72013-09-22 19:45:00 -0600442static const char *clockid[] = {
443 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300444 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
445 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600446};
447static DEFINE_STRARRAY(clockid);
448
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300449static const char *socket_families[] = {
450 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
451 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
452 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
453 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
454 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
455 "ALG", "NFC", "VSOCK",
456};
457static DEFINE_STRARRAY(socket_families);
458
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300459static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
460 struct syscall_arg *arg)
461{
462 size_t printed = 0;
463 int mode = arg->val;
464
465 if (mode == F_OK) /* 0 */
466 return scnprintf(bf, size, "F");
467#define P_MODE(n) \
468 if (mode & n##_OK) { \
469 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
470 mode &= ~n##_OK; \
471 }
472
473 P_MODE(R);
474 P_MODE(W);
475 P_MODE(X);
476#undef P_MODE
477
478 if (mode)
479 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
480
481 return printed;
482}
483
484#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
485
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300486static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
487 struct syscall_arg *arg);
488
489#define SCA_FILENAME syscall_arg__scnprintf_filename
490
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300491static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
492 struct syscall_arg *arg)
493{
494 int printed = 0, flags = arg->val;
495
496#define P_FLAG(n) \
497 if (flags & O_##n) { \
498 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
499 flags &= ~O_##n; \
500 }
501
502 P_FLAG(CLOEXEC);
503 P_FLAG(NONBLOCK);
504#undef P_FLAG
505
506 if (flags)
507 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
508
509 return printed;
510}
511
512#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
513
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300514#ifndef GRND_NONBLOCK
515#define GRND_NONBLOCK 0x0001
516#endif
517#ifndef GRND_RANDOM
518#define GRND_RANDOM 0x0002
519#endif
520
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300521static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
522 struct syscall_arg *arg)
523{
524 int printed = 0, flags = arg->val;
525
526#define P_FLAG(n) \
527 if (flags & GRND_##n) { \
528 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
529 flags &= ~GRND_##n; \
530 }
531
532 P_FLAG(RANDOM);
533 P_FLAG(NONBLOCK);
534#undef P_FLAG
535
536 if (flags)
537 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
538
539 return printed;
540}
541
542#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
543
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300544#define STRARRAY(name, array) \
545 { .scnprintf = SCA_STRARRAY, \
546 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300547
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300548#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300549#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300550#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300551#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300552#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300553#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300554#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300555#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300556#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300557#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300558#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300559#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300560#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300561#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300562
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300563struct syscall_arg_fmt {
564 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
565 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300566 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300567 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300568};
569
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300570static struct syscall_fmt {
571 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300572 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300573 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300574 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300575 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300576 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300577 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300578} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300579 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300580 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300581 { .name = "arch_prctl", .alias = "prctl", },
582 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300583 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300584 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300585 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300586 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300587 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300588 { .name = "clone", .errpid = true, .nr_args = 5,
589 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
590 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
591 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
592 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
593 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300594 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300595 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300596 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300597 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300598 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300599 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300600 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300601 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300602 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300603 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300604 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300605 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300606 .parm = &strarrays__fcntl_cmds_arrays,
607 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300608 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300609 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300610 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300611 { .name = "fstat", .alias = "newfstat", },
612 { .name = "fstatat", .alias = "newfstatat", },
613 { .name = "futex",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300614 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300615 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300616 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300617 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300618 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300619 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300620 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300621 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300622 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300623 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300624 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300625 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300626 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300627 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300628#if defined(__i386__) || defined(__x86_64__)
629/*
630 * FIXME: Make this available to all arches.
631 */
Arnaldo Carvalho de Melo1cc47f22017-07-31 13:20:14 -0300632 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300633 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300634#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300635 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300636#endif
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300637 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300638 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300639 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300640 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300641 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300642 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300643 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300644 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300645 { .name = "lstat", .alias = "newlstat", },
646 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300647 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
648 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300649 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300650 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300651 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300652 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300653 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300654 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300655 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300656 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300657 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200658/* The standard mmap maps to old_mmap on s390x */
659#if defined(__s390x__)
660 .alias = "old_mmap",
661#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300662 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
663 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
664 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300665 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300666 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
667 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300668 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300669 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300670 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300671 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
672 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
673 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300676 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300677 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300678 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300679 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300680 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300681 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300682 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300683 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300684 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300685 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
686 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300687 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300688 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
689 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300690 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300691 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
692 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
693 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300694 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300695 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300696 { .name = "poll", .timeout = true, },
697 { .name = "ppoll", .timeout = true, },
698 { .name = "pread", .alias = "pread64", },
699 { .name = "preadv", .alias = "pread", },
700 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300701 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300702 { .name = "pwrite", .alias = "pwrite64", },
703 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300705 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300706 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300707 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300708 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300710 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300711 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300717 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300718 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300719 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300720 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300721 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300722 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300723 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300724 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
725 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300726 { .name = "select", .timeout = true, },
727 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300728 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300730 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300731 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300732 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300733 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300734 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300735 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300736 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300737 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300738 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [0] = STRARRAY(family, socket_families),
740 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300741 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300742 .arg = { [0] = STRARRAY(family, socket_families),
743 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "stat", .alias = "newstat", },
745 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300746 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
747 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
748 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300750 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300751 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300752 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300753 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300754 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300755 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300756 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300757 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300758 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300759 { .name = "uname", .alias = "newuname", },
760 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300761 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300764 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300765 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300766 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300768};
769
770static int syscall_fmt__cmp(const void *name, const void *fmtp)
771{
772 const struct syscall_fmt *fmt = fmtp;
773 return strcmp(name, fmt->name);
774}
775
776static struct syscall_fmt *syscall_fmt__find(const char *name)
777{
778 const int nmemb = ARRAY_SIZE(syscall_fmts);
779 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
780}
781
782struct syscall {
783 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300784 int nr_args;
785 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300786 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300787 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300788 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300789 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300790};
791
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300792/*
793 * We need to have this 'calculated' boolean because in some cases we really
794 * don't know what is the duration of a syscall, for instance, when we start
795 * a session and some threads are waiting for a syscall to finish, say 'poll',
796 * in which case all we can do is to print "( ? ) for duration and for the
797 * start timestamp.
798 */
799static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200800{
801 double duration = (double)t / NSEC_PER_MSEC;
802 size_t printed = fprintf(fp, "(");
803
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300804 if (!calculated)
805 printed += fprintf(fp, " ? ");
806 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200807 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
808 else if (duration >= 0.01)
809 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
810 else
811 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300812 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200813}
814
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300815/**
816 * filename.ptr: The filename char pointer that will be vfs_getname'd
817 * filename.entry_str_pos: Where to insert the string translated from
818 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300819 * ret_scnprintf: syscall args may set this to a different syscall return
820 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300821 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300822struct thread_trace {
823 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300824 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300825 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400826 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300827 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300828 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300829 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300830 struct {
831 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300832 short int entry_str_pos;
833 bool pending_open;
834 unsigned int namelen;
835 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300836 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300837 struct {
838 int max;
839 char **table;
840 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600841
842 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300843};
844
845static struct thread_trace *thread_trace__new(void)
846{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300847 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
848
849 if (ttrace)
850 ttrace->paths.max = -1;
851
David Ahernbf2575c2013-10-08 21:26:53 -0600852 ttrace->syscall_stats = intlist__new(NULL);
853
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300854 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300855}
856
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300857static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300858{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300859 struct thread_trace *ttrace;
860
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300861 if (thread == NULL)
862 goto fail;
863
Namhyung Kim89dceb22014-10-06 09:46:03 +0900864 if (thread__priv(thread) == NULL)
865 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300866
Namhyung Kim89dceb22014-10-06 09:46:03 +0900867 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300868 goto fail;
869
Namhyung Kim89dceb22014-10-06 09:46:03 +0900870 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300871 ++ttrace->nr_events;
872
873 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300874fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300875 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876 "WARNING: not enough memory, dropping samples!\n");
877 return NULL;
878}
879
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300880
881void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300882 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300883{
884 struct thread_trace *ttrace = thread__priv(arg->thread);
885
886 ttrace->ret_scnprintf = ret_scnprintf;
887}
888
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400889#define TRACE_PFMAJ (1 << 0)
890#define TRACE_PFMIN (1 << 1)
891
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300892static const size_t trace__entry_str_size = 2048;
893
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300894static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300895{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900896 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300897
898 if (fd > ttrace->paths.max) {
899 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
900
901 if (npath == NULL)
902 return -1;
903
904 if (ttrace->paths.max != -1) {
905 memset(npath + ttrace->paths.max + 1, 0,
906 (fd - ttrace->paths.max) * sizeof(char *));
907 } else {
908 memset(npath, 0, (fd + 1) * sizeof(char *));
909 }
910
911 ttrace->paths.table = npath;
912 ttrace->paths.max = fd;
913 }
914
915 ttrace->paths.table[fd] = strdup(pathname);
916
917 return ttrace->paths.table[fd] != NULL ? 0 : -1;
918}
919
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300920static int thread__read_fd_path(struct thread *thread, int fd)
921{
922 char linkname[PATH_MAX], pathname[PATH_MAX];
923 struct stat st;
924 int ret;
925
926 if (thread->pid_ == thread->tid) {
927 scnprintf(linkname, sizeof(linkname),
928 "/proc/%d/fd/%d", thread->pid_, fd);
929 } else {
930 scnprintf(linkname, sizeof(linkname),
931 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
932 }
933
934 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
935 return -1;
936
937 ret = readlink(linkname, pathname, sizeof(pathname));
938
939 if (ret < 0 || ret > st.st_size)
940 return -1;
941
942 pathname[ret] = '\0';
943 return trace__set_fd_pathname(thread, fd, pathname);
944}
945
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300946static const char *thread__fd_path(struct thread *thread, int fd,
947 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300948{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900949 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300950
951 if (ttrace == NULL)
952 return NULL;
953
954 if (fd < 0)
955 return NULL;
956
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300957 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300958 if (!trace->live)
959 return NULL;
960 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300961 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300962 return NULL;
963 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300964
965 return ttrace->paths.table[fd];
966}
967
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -0300968size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300969{
970 int fd = arg->val;
971 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300972 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300973
974 if (path)
975 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
976
977 return printed;
978}
979
980static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
981 struct syscall_arg *arg)
982{
983 int fd = arg->val;
984 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +0900985 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300986
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300987 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
988 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300989
990 return printed;
991}
992
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300993static void thread__set_filename_pos(struct thread *thread, const char *bf,
994 unsigned long ptr)
995{
996 struct thread_trace *ttrace = thread__priv(thread);
997
998 ttrace->filename.ptr = ptr;
999 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1000}
1001
1002static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1003 struct syscall_arg *arg)
1004{
1005 unsigned long ptr = arg->val;
1006
1007 if (!arg->trace->vfs_getname)
1008 return scnprintf(bf, size, "%#x", ptr);
1009
1010 thread__set_filename_pos(arg->thread, bf, ptr);
1011 return 0;
1012}
1013
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001014static bool trace__filter_duration(struct trace *trace, double t)
1015{
1016 return t < (trace->duration_filter * NSEC_PER_MSEC);
1017}
1018
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001019static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001020{
1021 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1022
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001023 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001024}
1025
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001026/*
1027 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1028 * using ttrace->entry_time for a thread that receives a sys_exit without
1029 * first having received a sys_enter ("poll" issued before tracing session
1030 * starts, lost sys_enter exit due to ring buffer overflow).
1031 */
1032static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1033{
1034 if (tstamp > 0)
1035 return __trace__fprintf_tstamp(trace, tstamp, fp);
1036
1037 return fprintf(fp, " ? ");
1038}
1039
Namhyung Kimf15eb532012-10-05 14:02:16 +09001040static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001041static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001042
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001043static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001044{
1045 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001046 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001047}
1048
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001049static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001050 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001051{
1052 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001053 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001054
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001055 if (trace->multiple_threads) {
1056 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001057 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001058 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001059 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001060
1061 return printed;
1062}
1063
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001064static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001065 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001066{
1067 int ret = 0;
1068
1069 switch (event->header.type) {
1070 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001071 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001072 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001073 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001074 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001075 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001076 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001077 break;
1078 }
1079
1080 return ret;
1081}
1082
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001083static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001085 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086 struct machine *machine)
1087{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001088 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001089 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001090}
1091
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001092static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1093{
1094 struct machine *machine = vmachine;
1095
1096 if (machine->kptr_restrict_warned)
1097 return NULL;
1098
1099 if (symbol_conf.kptr_restrict) {
1100 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1101 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1102 "Kernel samples will not be resolved.\n");
1103 machine->kptr_restrict_warned = true;
1104 return NULL;
1105 }
1106
1107 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1108}
1109
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1111{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001112 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113
1114 if (err)
1115 return err;
1116
David Ahern8fb598e2013-09-28 13:13:00 -06001117 trace->host = machine__new_host();
1118 if (trace->host == NULL)
1119 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001121 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001122 return -errno;
1123
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001124 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001125 evlist->threads, trace__tool_process, false,
1126 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127 if (err)
1128 symbol__exit();
1129
1130 return err;
1131}
1132
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001133static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1134{
1135 int idx;
1136
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001137 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1138 nr_args = sc->fmt->nr_args;
1139
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001140 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1141 if (sc->arg_fmt == NULL)
1142 return -1;
1143
1144 for (idx = 0; idx < nr_args; ++idx) {
1145 if (sc->fmt)
1146 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1147 }
1148
1149 sc->nr_args = nr_args;
1150 return 0;
1151}
1152
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001153static int syscall__set_arg_fmts(struct syscall *sc)
1154{
1155 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001156 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001157
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001158 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001159 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1160 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001161
1162 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001163 (strcmp(field->name, "filename") == 0 ||
1164 strcmp(field->name, "path") == 0 ||
1165 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001166 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001167 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001168 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001169 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001170 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001171 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001172 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001173 else if ((strcmp(field->type, "int") == 0 ||
1174 strcmp(field->type, "unsigned int") == 0 ||
1175 strcmp(field->type, "long") == 0) &&
1176 (len = strlen(field->name)) >= 2 &&
1177 strcmp(field->name + len - 2, "fd") == 0) {
1178 /*
1179 * /sys/kernel/tracing/events/syscalls/sys_enter*
1180 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1181 * 65 int
1182 * 23 unsigned int
1183 * 7 unsigned long
1184 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001185 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001186 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001187 }
1188
1189 return 0;
1190}
1191
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001192static int trace__read_syscall_info(struct trace *trace, int id)
1193{
1194 char tp_name[128];
1195 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001196 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001197
1198 if (name == NULL)
1199 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001200
1201 if (id > trace->syscalls.max) {
1202 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1203
1204 if (nsyscalls == NULL)
1205 return -1;
1206
1207 if (trace->syscalls.max != -1) {
1208 memset(nsyscalls + trace->syscalls.max + 1, 0,
1209 (id - trace->syscalls.max) * sizeof(*sc));
1210 } else {
1211 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1212 }
1213
1214 trace->syscalls.table = nsyscalls;
1215 trace->syscalls.max = id;
1216 }
1217
1218 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001219 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001220
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001221 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001222
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001223 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001224 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001225
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001226 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001227 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001228 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001229 }
1230
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001231 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1232 return -1;
1233
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001234 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001235 return -1;
1236
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001237 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001238 /*
1239 * We need to check and discard the first variable '__syscall_nr'
1240 * or 'nr' that mean the syscall number. It is needless here.
1241 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1242 */
1243 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001244 sc->args = sc->args->next;
1245 --sc->nr_args;
1246 }
1247
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001248 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1249
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001250 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001251}
1252
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001253static int trace__validate_ev_qualifier(struct trace *trace)
1254{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001255 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001256 struct str_node *pos;
1257
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001258 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1259 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1260 sizeof(trace->ev_qualifier_ids.entries[0]));
1261
1262 if (trace->ev_qualifier_ids.entries == NULL) {
1263 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1264 trace->output);
1265 err = -EINVAL;
1266 goto out;
1267 }
1268
1269 i = 0;
1270
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001271 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001272 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001273 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001274
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001275 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001276 if (err == 0) {
1277 fputs("Error:\tInvalid syscall ", trace->output);
1278 err = -EINVAL;
1279 } else {
1280 fputs(", ", trace->output);
1281 }
1282
1283 fputs(sc, trace->output);
1284 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001285
1286 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001287 }
1288
1289 if (err < 0) {
1290 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1291 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001292 zfree(&trace->ev_qualifier_ids.entries);
1293 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001294 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001295out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001296 return err;
1297}
1298
David Ahern55d43bca2015-02-19 15:00:22 -05001299/*
1300 * args is to be interpreted as a series of longs but we need to handle
1301 * 8-byte unaligned accesses. args points to raw_data within the event
1302 * and raw_data is guaranteed to be 8-byte unaligned because it is
1303 * preceded by raw_size which is a u32. So we need to copy args to a temp
1304 * variable to read it. Most notably this avoids extended load instructions
1305 * on unaligned addresses
1306 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001307unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001308{
1309 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001310 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001311
1312 memcpy(&val, p, sizeof(val));
1313 return val;
1314}
1315
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001316static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1317 struct syscall_arg *arg)
1318{
1319 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1320 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1321
1322 return scnprintf(bf, size, "arg%d: ", arg->idx);
1323}
1324
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001325static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1326 struct syscall_arg *arg, unsigned long val)
1327{
1328 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1329 arg->val = val;
1330 if (sc->arg_fmt[arg->idx].parm)
1331 arg->parm = sc->arg_fmt[arg->idx].parm;
1332 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1333 }
1334 return scnprintf(bf, size, "%ld", val);
1335}
1336
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001337static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001338 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001339 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001340{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001341 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001342 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001343 u8 bit = 1;
1344 struct syscall_arg arg = {
1345 .args = args,
1346 .idx = 0,
1347 .mask = 0,
1348 .trace = trace,
1349 .thread = thread,
1350 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001351 struct thread_trace *ttrace = thread__priv(thread);
1352
1353 /*
1354 * Things like fcntl will set this in its 'cmd' formatter to pick the
1355 * right formatter for the return value (an fd? file flags?), which is
1356 * not needed for syscalls that always return a given type, say an fd.
1357 */
1358 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001359
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001360 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001361 struct format_field *field;
1362
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001363 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001364 field = field->next, ++arg.idx, bit <<= 1) {
1365 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001366 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001367
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001368 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001369
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001370 /*
1371 * Suppress this argument if its value is zero and
1372 * and we don't have a string associated in an
1373 * strarray for it.
1374 */
David Ahern55d43bca2015-02-19 15:00:22 -05001375 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001376 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001377 (sc->arg_fmt[arg.idx].show_zero ||
1378 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001379 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1380 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001381 continue;
1382
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001383 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001384 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001385 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001387 } else if (IS_ERR(sc->tp_format)) {
1388 /*
1389 * If we managed to read the tracepoint /format file, then we
1390 * may end up not having any args, like with gettid(), so only
1391 * print the raw args when we didn't manage to read it.
1392 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001393 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001394 if (arg.mask & bit)
1395 goto next_arg;
1396 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001397 if (printed)
1398 printed += scnprintf(bf + printed, size - printed, ", ");
1399 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001400 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1401next_arg:
1402 ++arg.idx;
1403 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001404 }
1405 }
1406
1407 return printed;
1408}
1409
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001410typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001411 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001412 struct perf_sample *sample);
1413
1414static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001415 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001416{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001417
1418 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001419
1420 /*
1421 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1422 * before that, leaving at a higher verbosity level till that is
1423 * explained. Reproduced with plain ftrace with:
1424 *
1425 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1426 * grep "NR -1 " /t/trace_pipe
1427 *
1428 * After generating some load on the machine.
1429 */
1430 if (verbose > 1) {
1431 static u64 n;
1432 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1433 id, perf_evsel__name(evsel), ++n);
1434 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001435 return NULL;
1436 }
1437
1438 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1439 trace__read_syscall_info(trace, id))
1440 goto out_cant_read;
1441
1442 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1443 goto out_cant_read;
1444
1445 return &trace->syscalls.table[id];
1446
1447out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001448 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001449 fprintf(trace->output, "Problems reading syscall %d", id);
1450 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1451 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1452 fputs(" information\n", trace->output);
1453 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001454 return NULL;
1455}
1456
David Ahernbf2575c2013-10-08 21:26:53 -06001457static void thread__update_stats(struct thread_trace *ttrace,
1458 int id, struct perf_sample *sample)
1459{
1460 struct int_node *inode;
1461 struct stats *stats;
1462 u64 duration = 0;
1463
1464 inode = intlist__findnew(ttrace->syscall_stats, id);
1465 if (inode == NULL)
1466 return;
1467
1468 stats = inode->priv;
1469 if (stats == NULL) {
1470 stats = malloc(sizeof(struct stats));
1471 if (stats == NULL)
1472 return;
1473 init_stats(stats);
1474 inode->priv = stats;
1475 }
1476
1477 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1478 duration = sample->time - ttrace->entry_time;
1479
1480 update_stats(stats, duration);
1481}
1482
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001483static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1484{
1485 struct thread_trace *ttrace;
1486 u64 duration;
1487 size_t printed;
1488
1489 if (trace->current == NULL)
1490 return 0;
1491
1492 ttrace = thread__priv(trace->current);
1493
1494 if (!ttrace->entry_pending)
1495 return 0;
1496
1497 duration = sample->time - ttrace->entry_time;
1498
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001499 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001500 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1501 ttrace->entry_pending = false;
1502
1503 return printed;
1504}
1505
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001506static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001507 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001508 struct perf_sample *sample)
1509{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001510 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001511 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001512 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001513 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001514 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001515 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001516 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001517
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001518 if (sc == NULL)
1519 return -1;
1520
David Ahern8fb598e2013-09-28 13:13:00 -06001521 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001522 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001523 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001524 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001525
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001526 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001527
1528 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001529 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001530 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001531 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001532 }
1533
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001534 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001535 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001536
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001537 ttrace->entry_time = sample->time;
1538 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001539 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001540
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001541 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001542 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001543
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001544 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001545 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001546 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001547 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001548 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001549 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001550 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001551 /* See trace__vfs_getname & trace__sys_exit */
1552 ttrace->filename.pending_open = false;
1553 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001554
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001555 if (trace->current != thread) {
1556 thread__put(trace->current);
1557 trace->current = thread__get(thread);
1558 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001559 err = 0;
1560out_put:
1561 thread__put(thread);
1562 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001563}
1564
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001565static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1566 struct perf_sample *sample,
1567 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001568{
1569 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001570
1571 if (machine__resolve(trace->host, &al, sample) < 0 ||
1572 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1573 return -1;
1574
1575 return 0;
1576}
1577
1578static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1579{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001580 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001581 const unsigned int print_opts = EVSEL__PRINT_SYM |
1582 EVSEL__PRINT_DSO |
1583 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001584
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001585 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001586}
1587
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001588static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001589 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001590 struct perf_sample *sample)
1591{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001592 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001593 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001594 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001595 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001596 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001597 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001598 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001599
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001600 if (sc == NULL)
1601 return -1;
1602
David Ahern8fb598e2013-09-28 13:13:00 -06001603 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001604 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001605 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001606 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001607
David Ahernbf2575c2013-10-08 21:26:53 -06001608 if (trace->summary)
1609 thread__update_stats(ttrace, id, sample);
1610
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001611 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001612
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001613 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001614 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1615 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001616 ++trace->stats.vfs_getname;
1617 }
1618
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001619 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001620 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001621 if (trace__filter_duration(trace, duration))
1622 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001623 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001624 } else if (trace->duration_filter)
1625 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001626
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001627 if (sample->callchain) {
1628 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1629 if (callchain_ret == 0) {
1630 if (callchain_cursor.nr < trace->min_stack)
1631 goto out;
1632 callchain_ret = 1;
1633 }
1634 }
1635
David Ahernfd2eaba2013-11-12 09:31:15 -07001636 if (trace->summary_only)
1637 goto out;
1638
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001639 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001640
1641 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001642 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001643 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001644 fprintf(trace->output, " ... [");
1645 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1646 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001647 }
1648
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001649 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001650 if (ret < 0)
1651 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001652signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001653 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001654 } else if (ret < 0) {
1655errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001656 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001657 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001658 *e = audit_errno_to_name(-ret);
1659
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001660 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001661 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001662 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001663 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001664 else if (ttrace->ret_scnprintf) {
1665 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001666 struct syscall_arg arg = {
1667 .val = ret,
1668 .thread = thread,
1669 .trace = trace,
1670 };
1671 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001672 ttrace->ret_scnprintf = NULL;
1673 fprintf(trace->output, ") = %s", bf);
1674 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001675 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001676 else if (sc->fmt->errpid) {
1677 struct thread *child = machine__find_thread(trace->host, ret, ret);
1678
1679 if (child != NULL) {
1680 fprintf(trace->output, ") = %ld", ret);
1681 if (child->comm_set)
1682 fprintf(trace->output, " (%s)", thread__comm_str(child));
1683 thread__put(child);
1684 }
1685 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001686 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001687
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001688 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001689
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001690 if (callchain_ret > 0)
1691 trace__fprintf_callchain(trace, sample);
1692 else if (callchain_ret < 0)
1693 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001694out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001695 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001696 err = 0;
1697out_put:
1698 thread__put(thread);
1699 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001700}
1701
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001702static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001703 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001704 struct perf_sample *sample)
1705{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001706 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1707 struct thread_trace *ttrace;
1708 size_t filename_len, entry_str_len, to_move;
1709 ssize_t remaining_space;
1710 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001711 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001712
1713 if (!thread)
1714 goto out;
1715
1716 ttrace = thread__priv(thread);
1717 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001718 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001719
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001720 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001721 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001722 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001723
1724 if (ttrace->filename.namelen < filename_len) {
1725 char *f = realloc(ttrace->filename.name, filename_len + 1);
1726
1727 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001728 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001729
1730 ttrace->filename.namelen = filename_len;
1731 ttrace->filename.name = f;
1732 }
1733
1734 strcpy(ttrace->filename.name, filename);
1735 ttrace->filename.pending_open = true;
1736
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001737 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001738 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001739
1740 entry_str_len = strlen(ttrace->entry_str);
1741 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1742 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001743 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001744
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001745 if (filename_len > (size_t)remaining_space) {
1746 filename += filename_len - remaining_space;
1747 filename_len = remaining_space;
1748 }
1749
1750 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1751 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1752 memmove(pos + filename_len, pos, to_move);
1753 memcpy(pos, filename, filename_len);
1754
1755 ttrace->filename.ptr = 0;
1756 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001757out_put:
1758 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001759out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001760 return 0;
1761}
1762
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001763static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001764 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001765 struct perf_sample *sample)
1766{
1767 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1768 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001769 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001770 sample->pid,
1771 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001772 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001773
1774 if (ttrace == NULL)
1775 goto out_dump;
1776
1777 ttrace->runtime_ms += runtime_ms;
1778 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001779out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001780 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001781 return 0;
1782
1783out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001784 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001785 evsel->name,
1786 perf_evsel__strval(evsel, sample, "comm"),
1787 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1788 runtime,
1789 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001790 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001791}
1792
Wang Nan1d6c9402016-02-26 09:31:55 +00001793static void bpf_output__printer(enum binary_printer_ops op,
1794 unsigned int val, void *extra)
1795{
1796 FILE *output = extra;
1797 unsigned char ch = (unsigned char)val;
1798
1799 switch (op) {
1800 case BINARY_PRINT_CHAR_DATA:
1801 fprintf(output, "%c", isprint(ch) ? ch : '.');
1802 break;
1803 case BINARY_PRINT_DATA_BEGIN:
1804 case BINARY_PRINT_LINE_BEGIN:
1805 case BINARY_PRINT_ADDR:
1806 case BINARY_PRINT_NUM_DATA:
1807 case BINARY_PRINT_NUM_PAD:
1808 case BINARY_PRINT_SEP:
1809 case BINARY_PRINT_CHAR_PAD:
1810 case BINARY_PRINT_LINE_END:
1811 case BINARY_PRINT_DATA_END:
1812 default:
1813 break;
1814 }
1815}
1816
1817static void bpf_output__fprintf(struct trace *trace,
1818 struct perf_sample *sample)
1819{
1820 print_binary(sample->raw_data, sample->raw_size, 8,
1821 bpf_output__printer, trace->output);
1822}
1823
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001824static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1825 union perf_event *event __maybe_unused,
1826 struct perf_sample *sample)
1827{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001828 int callchain_ret = 0;
1829
1830 if (sample->callchain) {
1831 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1832 if (callchain_ret == 0) {
1833 if (callchain_cursor.nr < trace->min_stack)
1834 goto out;
1835 callchain_ret = 1;
1836 }
1837 }
1838
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001839 trace__printf_interrupted_entry(trace, sample);
1840 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001841
1842 if (trace->trace_syscalls)
1843 fprintf(trace->output, "( ): ");
1844
1845 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001846
Wang Nan1d6c9402016-02-26 09:31:55 +00001847 if (perf_evsel__is_bpf_output(evsel)) {
1848 bpf_output__fprintf(trace, sample);
1849 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001850 event_format__fprintf(evsel->tp_format, sample->cpu,
1851 sample->raw_data, sample->raw_size,
1852 trace->output);
1853 }
1854
1855 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001856
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001857 if (callchain_ret > 0)
1858 trace__fprintf_callchain(trace, sample);
1859 else if (callchain_ret < 0)
1860 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1861out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001862 return 0;
1863}
1864
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001865static void print_location(FILE *f, struct perf_sample *sample,
1866 struct addr_location *al,
1867 bool print_dso, bool print_sym)
1868{
1869
Namhyung Kimbb963e12017-02-17 17:17:38 +09001870 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001871 fprintf(f, "%s@", al->map->dso->long_name);
1872
Namhyung Kimbb963e12017-02-17 17:17:38 +09001873 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001874 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001875 al->addr - al->sym->start);
1876 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001877 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001878 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001879 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001880}
1881
1882static int trace__pgfault(struct trace *trace,
1883 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001884 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001885 struct perf_sample *sample)
1886{
1887 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888 struct addr_location al;
1889 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001890 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001891 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001892 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001893
1894 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001895
1896 if (sample->callchain) {
1897 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1898 if (callchain_ret == 0) {
1899 if (callchain_cursor.nr < trace->min_stack)
1900 goto out_put;
1901 callchain_ret = 1;
1902 }
1903 }
1904
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001905 ttrace = thread__trace(thread, trace->output);
1906 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001907 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001908
1909 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1910 ttrace->pfmaj++;
1911 else
1912 ttrace->pfmin++;
1913
1914 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001915 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001916
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001917 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001918 sample->ip, &al);
1919
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001920 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001921
1922 fprintf(trace->output, "%sfault [",
1923 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1924 "maj" : "min");
1925
1926 print_location(trace->output, sample, &al, false, true);
1927
1928 fprintf(trace->output, "] => ");
1929
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001930 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001931 sample->addr, &al);
1932
1933 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001934 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001935 MAP__FUNCTION, sample->addr, &al);
1936
1937 if (al.map)
1938 map_type = 'x';
1939 else
1940 map_type = '?';
1941 }
1942
1943 print_location(trace->output, sample, &al, true, false);
1944
1945 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001946
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001947 if (callchain_ret > 0)
1948 trace__fprintf_callchain(trace, sample);
1949 else if (callchain_ret < 0)
1950 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001951out:
1952 err = 0;
1953out_put:
1954 thread__put(thread);
1955 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001956}
1957
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001958static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001959 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001960 struct perf_sample *sample)
1961{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001962 /*
1963 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1964 * and don't use sample->time unconditionally, we may end up having
1965 * some other event in the future without PERF_SAMPLE_TIME for good
1966 * reason, i.e. we may not be interested in its timestamps, just in
1967 * it taking place, picking some piece of information when it
1968 * appears in our event stream (vfs_getname comes to mind).
1969 */
1970 if (trace->base_time == 0 && !trace->full_time &&
1971 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001972 trace->base_time = sample->time;
1973}
1974
David Ahern6810fc92013-08-28 22:29:52 -06001975static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001976 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001977 struct perf_sample *sample,
1978 struct perf_evsel *evsel,
1979 struct machine *machine __maybe_unused)
1980{
1981 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001982 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001983 int err = 0;
1984
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001985 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001986
David Ahernaa07df62016-11-25 09:29:52 -07001987 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1988 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001989 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06001990
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001991 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06001992
David Ahern31605652013-12-04 19:41:41 -07001993 if (handler) {
1994 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001995 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07001996 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001997out:
1998 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06001999 return err;
2000}
2001
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002002static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002003{
2004 unsigned int rec_argc, i, j;
2005 const char **rec_argv;
2006 const char * const record_args[] = {
2007 "record",
2008 "-R",
2009 "-m", "1024",
2010 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002011 };
2012
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002013 const char * const sc_args[] = { "-e", };
2014 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2015 const char * const majpf_args[] = { "-e", "major-faults" };
2016 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2017 const char * const minpf_args[] = { "-e", "minor-faults" };
2018 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2019
David Ahern9aca7f12013-12-04 19:41:39 -07002020 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002021 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2022 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002023 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2024
2025 if (rec_argv == NULL)
2026 return -ENOMEM;
2027
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002028 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002029 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002030 rec_argv[j++] = record_args[i];
2031
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002032 if (trace->trace_syscalls) {
2033 for (i = 0; i < sc_args_nr; i++)
2034 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002035
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002036 /* event string may be different for older kernels - e.g., RHEL6 */
2037 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2038 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2039 else if (is_valid_tracepoint("syscalls:sys_enter"))
2040 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2041 else {
2042 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2043 return -1;
2044 }
David Ahern9aca7f12013-12-04 19:41:39 -07002045 }
David Ahern9aca7f12013-12-04 19:41:39 -07002046
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002047 if (trace->trace_pgfaults & TRACE_PFMAJ)
2048 for (i = 0; i < majpf_args_nr; i++)
2049 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002050
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002051 if (trace->trace_pgfaults & TRACE_PFMIN)
2052 for (i = 0; i < minpf_args_nr; i++)
2053 rec_argv[j++] = minpf_args[i];
2054
2055 for (i = 0; i < (unsigned int)argc; i++)
2056 rec_argv[j++] = argv[i];
2057
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002058 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002059}
2060
David Ahernbf2575c2013-10-08 21:26:53 -06002061static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2062
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002063static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002064{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002065 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002066
2067 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002068 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002069
2070 if (perf_evsel__field(evsel, "pathname") == NULL) {
2071 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002072 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002073 }
2074
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002075 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002076 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002077 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002078}
2079
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002080static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002081{
2082 struct perf_evsel *evsel;
2083 struct perf_event_attr attr = {
2084 .type = PERF_TYPE_SOFTWARE,
2085 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002086 };
2087
2088 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002089 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002090
2091 event_attr_init(&attr);
2092
2093 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002094 if (evsel)
2095 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002096
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002097 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002098}
2099
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002100static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2101{
2102 const u32 type = event->header.type;
2103 struct perf_evsel *evsel;
2104
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002105 if (type != PERF_RECORD_SAMPLE) {
2106 trace__process_event(trace, trace->host, event, sample);
2107 return;
2108 }
2109
2110 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2111 if (evsel == NULL) {
2112 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2113 return;
2114 }
2115
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002116 trace__set_base_time(trace, evsel, sample);
2117
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002118 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2119 sample->raw_data == NULL) {
2120 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2121 perf_evsel__name(evsel), sample->tid,
2122 sample->cpu, sample->raw_size);
2123 } else {
2124 tracepoint_handler handler = evsel->handler;
2125 handler(trace, evsel, event, sample);
2126 }
2127}
2128
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002129static int trace__add_syscall_newtp(struct trace *trace)
2130{
2131 int ret = -1;
2132 struct perf_evlist *evlist = trace->evlist;
2133 struct perf_evsel *sys_enter, *sys_exit;
2134
2135 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2136 if (sys_enter == NULL)
2137 goto out;
2138
2139 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2140 goto out_delete_sys_enter;
2141
2142 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2143 if (sys_exit == NULL)
2144 goto out_delete_sys_enter;
2145
2146 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2147 goto out_delete_sys_exit;
2148
2149 perf_evlist__add(evlist, sys_enter);
2150 perf_evlist__add(evlist, sys_exit);
2151
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002152 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002153 /*
2154 * We're interested only in the user space callchain
2155 * leading to the syscall, allow overriding that for
2156 * debugging reasons using --kernel_syscall_callchains
2157 */
2158 sys_exit->attr.exclude_callchain_kernel = 1;
2159 }
2160
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002161 trace->syscalls.events.sys_enter = sys_enter;
2162 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002163
2164 ret = 0;
2165out:
2166 return ret;
2167
2168out_delete_sys_exit:
2169 perf_evsel__delete_priv(sys_exit);
2170out_delete_sys_enter:
2171 perf_evsel__delete_priv(sys_enter);
2172 goto out;
2173}
2174
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002175static int trace__set_ev_qualifier_filter(struct trace *trace)
2176{
2177 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002178 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002179 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2180 trace->ev_qualifier_ids.nr,
2181 trace->ev_qualifier_ids.entries);
2182
2183 if (filter == NULL)
2184 goto out_enomem;
2185
Mathieu Poirier3541c032016-09-16 08:44:04 -06002186 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2187 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002188 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002189 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002190 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002191
2192 free(filter);
2193out:
2194 return err;
2195out_enomem:
2196 errno = ENOMEM;
2197 goto out;
2198}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002199
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002200static int trace__set_filter_loop_pids(struct trace *trace)
2201{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002202 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002203 pid_t pids[32] = {
2204 getpid(),
2205 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002206 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2207
2208 while (thread && nr < ARRAY_SIZE(pids)) {
2209 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2210
2211 if (parent == NULL)
2212 break;
2213
2214 if (!strcmp(thread__comm_str(parent), "sshd")) {
2215 pids[nr++] = parent->tid;
2216 break;
2217 }
2218 thread = parent;
2219 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002220
2221 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2222}
2223
Namhyung Kimf15eb532012-10-05 14:02:16 +09002224static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002225{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002226 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002227 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002228 int err = -1, i;
2229 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002230 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002231 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002232
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002233 trace->live = true;
2234
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002235 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002236 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002237
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002238 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002239 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002240
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002241 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2242 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2243 if (pgfault_maj == NULL)
2244 goto out_error_mem;
2245 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002246 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002247
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002248 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2249 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2250 if (pgfault_min == NULL)
2251 goto out_error_mem;
2252 perf_evlist__add(evlist, pgfault_min);
2253 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002254
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002255 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002256 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2257 trace__sched_stat_runtime))
2258 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002259
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002260 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2261 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002262 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002263 goto out_delete_evlist;
2264 }
2265
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002266 err = trace__symbols_init(trace, evlist);
2267 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002268 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002269 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002270 }
2271
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002272 perf_evlist__config(evlist, &trace->opts, NULL);
2273
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002274 if (callchain_param.enabled) {
2275 bool use_identifier = false;
2276
2277 if (trace->syscalls.events.sys_exit) {
2278 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2279 &trace->opts, &callchain_param);
2280 use_identifier = true;
2281 }
2282
2283 if (pgfault_maj) {
2284 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2285 use_identifier = true;
2286 }
2287
2288 if (pgfault_min) {
2289 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2290 use_identifier = true;
2291 }
2292
2293 if (use_identifier) {
2294 /*
2295 * Now we have evsels with different sample_ids, use
2296 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2297 * from a fixed position in each ring buffer record.
2298 *
2299 * As of this the changeset introducing this comment, this
2300 * isn't strictly needed, as the fields that can come before
2301 * PERF_SAMPLE_ID are all used, but we'll probably disable
2302 * some of those for things like copying the payload of
2303 * pointer syscall arguments, and for vfs_getname we don't
2304 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2305 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2306 */
2307 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2308 perf_evlist__reset_sample_bit(evlist, ID);
2309 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002310 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002311
Namhyung Kimf15eb532012-10-05 14:02:16 +09002312 signal(SIGCHLD, sig_handler);
2313 signal(SIGINT, sig_handler);
2314
2315 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002316 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002317 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002318 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002319 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002320 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002321 }
2322 }
2323
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002324 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002325 if (err < 0)
2326 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002327
Wang Nanba504232016-02-26 09:31:54 +00002328 err = bpf__apply_obj_config();
2329 if (err) {
2330 char errbuf[BUFSIZ];
2331
2332 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2333 pr_err("ERROR: Apply config to BPF failed: %s\n",
2334 errbuf);
2335 goto out_error_open;
2336 }
2337
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002338 /*
2339 * Better not use !target__has_task() here because we need to cover the
2340 * case where no threads were specified in the command line, but a
2341 * workload was, and in that case we will fill in the thread_map when
2342 * we fork the workload in perf_evlist__prepare_workload.
2343 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002344 if (trace->filter_pids.nr > 0)
2345 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002346 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002347 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002348
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002349 if (err < 0)
2350 goto out_error_mem;
2351
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002352 if (trace->ev_qualifier_ids.nr > 0) {
2353 err = trace__set_ev_qualifier_filter(trace);
2354 if (err < 0)
2355 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002356
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002357 pr_debug("event qualifier tracepoint filter: %s\n",
2358 trace->syscalls.events.sys_exit->filter);
2359 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002360
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002361 err = perf_evlist__apply_filters(evlist, &evsel);
2362 if (err < 0)
2363 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002364
Jiri Olsaf8850372013-11-28 17:57:22 +01002365 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002366 if (err < 0)
2367 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002368
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002369 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002370 perf_evlist__enable(evlist);
2371
Namhyung Kimf15eb532012-10-05 14:02:16 +09002372 if (forks)
2373 perf_evlist__start_workload(evlist);
2374
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002375 if (trace->opts.initial_delay) {
2376 usleep(trace->opts.initial_delay * 1000);
2377 perf_evlist__enable(evlist);
2378 }
2379
Jiri Olsae13798c2015-06-23 00:36:02 +02002380 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002381 evlist->threads->nr > 1 ||
2382 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002383again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002384 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002385
2386 for (i = 0; i < evlist->nr_mmaps; i++) {
2387 union perf_event *event;
2388
2389 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002390 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002391
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002392 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002393
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002394 err = perf_evlist__parse_sample(evlist, event, &sample);
2395 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002396 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002397 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002398 }
2399
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002400 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002401next_event:
2402 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002403
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002404 if (interrupted)
2405 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002406
2407 if (done && !draining) {
2408 perf_evlist__disable(evlist);
2409 draining = true;
2410 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002411 }
2412 }
2413
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002414 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002415 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002416
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002417 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2418 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2419 draining = true;
2420
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002421 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002422 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002423 } else {
2424 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002425 }
2426
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002427out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002428 thread__zput(trace->current);
2429
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002430 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002431
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002432 if (!err) {
2433 if (trace->summary)
2434 trace__fprintf_thread_summary(trace, trace->output);
2435
2436 if (trace->show_tool_stats) {
2437 fprintf(trace->output, "Stats:\n "
2438 " vfs_getname : %" PRIu64 "\n"
2439 " proc_getname: %" PRIu64 "\n",
2440 trace->stats.vfs_getname,
2441 trace->stats.proc_getname);
2442 }
2443 }
David Ahernbf2575c2013-10-08 21:26:53 -06002444
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002445out_delete_evlist:
2446 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002447 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002448 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002449 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002450{
2451 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002452
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002453out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002454 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002455 goto out_error;
2456
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002457out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002458 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002459 goto out_error;
2460
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002461out_error_mmap:
2462 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2463 goto out_error;
2464
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002465out_error_open:
2466 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2467
2468out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002469 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302470 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002471
2472out_error_apply_filters:
2473 fprintf(trace->output,
2474 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2475 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002476 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002477 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002478}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002479out_error_mem:
2480 fprintf(trace->output, "Not enough memory to run!\n");
2481 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002482
2483out_errno:
2484 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2485 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002486}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002487
David Ahern6810fc92013-08-28 22:29:52 -06002488static int trace__replay(struct trace *trace)
2489{
2490 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002491 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002492 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002493 struct perf_data_file file = {
2494 .path = input_name,
2495 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002496 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002497 };
David Ahern6810fc92013-08-28 22:29:52 -06002498 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002499 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002500 int err = -1;
2501
2502 trace->tool.sample = trace__process_sample;
2503 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002504 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002505 trace->tool.comm = perf_event__process_comm;
2506 trace->tool.exit = perf_event__process_exit;
2507 trace->tool.fork = perf_event__process_fork;
2508 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302509 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002510 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302511 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002512
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002513 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002514 trace->tool.ordering_requires_timestamps = true;
2515
2516 /* add tid to output */
2517 trace->multiple_threads = true;
2518
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002519 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002520 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002521 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002522
David Ahernaa07df62016-11-25 09:29:52 -07002523 if (trace->opts.target.pid)
2524 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2525
2526 if (trace->opts.target.tid)
2527 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2528
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002529 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002530 goto out;
2531
David Ahern8fb598e2013-09-28 13:13:00 -06002532 trace->host = &session->machines.host;
2533
David Ahern6810fc92013-08-28 22:29:52 -06002534 err = perf_session__set_tracepoints_handlers(session, handlers);
2535 if (err)
2536 goto out;
2537
Namhyung Kim003824e2013-11-12 15:25:00 +09002538 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2539 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002540 /* older kernels have syscalls tp versus raw_syscalls */
2541 if (evsel == NULL)
2542 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2543 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002544
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002545 if (evsel &&
2546 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2547 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002548 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2549 goto out;
2550 }
2551
2552 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2553 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002554 if (evsel == NULL)
2555 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2556 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002557 if (evsel &&
2558 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2559 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002560 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002561 goto out;
2562 }
2563
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002564 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002565 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2566 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2567 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2568 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2569 evsel->handler = trace__pgfault;
2570 }
2571
David Ahern6810fc92013-08-28 22:29:52 -06002572 setup_pager();
2573
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002574 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002575 if (err)
2576 pr_err("Failed to process events, error %d", err);
2577
David Ahernbf2575c2013-10-08 21:26:53 -06002578 else if (trace->summary)
2579 trace__fprintf_thread_summary(trace, trace->output);
2580
David Ahern6810fc92013-08-28 22:29:52 -06002581out:
2582 perf_session__delete(session);
2583
2584 return err;
2585}
2586
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002587static size_t trace__fprintf_threads_header(FILE *fp)
2588{
2589 size_t printed;
2590
Pekka Enberg99ff7152013-11-12 16:42:14 +02002591 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002592
2593 return printed;
2594}
2595
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002596DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2597 struct stats *stats;
2598 double msecs;
2599 int syscall;
2600)
2601{
2602 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2603 struct stats *stats = source->priv;
2604
2605 entry->syscall = source->i;
2606 entry->stats = stats;
2607 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2608}
2609
David Ahernbf2575c2013-10-08 21:26:53 -06002610static size_t thread__dump_stats(struct thread_trace *ttrace,
2611 struct trace *trace, FILE *fp)
2612{
David Ahernbf2575c2013-10-08 21:26:53 -06002613 size_t printed = 0;
2614 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002615 struct rb_node *nd;
2616 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002617
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002618 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002619 return 0;
2620
2621 printed += fprintf(fp, "\n");
2622
Milian Wolff834fd462015-08-06 11:24:29 +02002623 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2624 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2625 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002626
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002627 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002628 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002629 if (stats) {
2630 double min = (double)(stats->min) / NSEC_PER_MSEC;
2631 double max = (double)(stats->max) / NSEC_PER_MSEC;
2632 double avg = avg_stats(stats);
2633 double pct;
2634 u64 n = (u64) stats->n;
2635
2636 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2637 avg /= NSEC_PER_MSEC;
2638
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002639 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002640 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002641 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002642 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002643 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002644 }
David Ahernbf2575c2013-10-08 21:26:53 -06002645 }
2646
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002647 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002648 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002649
2650 return printed;
2651}
2652
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002653static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002654{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002655 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002656 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002657 double ratio;
2658
2659 if (ttrace == NULL)
2660 return 0;
2661
2662 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2663
Pekka Enberg15e65c62013-11-14 18:43:30 +02002664 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002665 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002666 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002667 if (ttrace->pfmaj)
2668 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2669 if (ttrace->pfmin)
2670 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002671 if (trace->sched)
2672 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2673 else if (fputc('\n', fp) != EOF)
2674 ++printed;
2675
David Ahernbf2575c2013-10-08 21:26:53 -06002676 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002677
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002678 return printed;
2679}
David Ahern896cbb52013-09-28 13:12:59 -06002680
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002681static unsigned long thread__nr_events(struct thread_trace *ttrace)
2682{
2683 return ttrace ? ttrace->nr_events : 0;
2684}
2685
2686DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2687 struct thread *thread;
2688)
2689{
2690 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002691}
2692
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002693static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2694{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002695 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2696 size_t printed = trace__fprintf_threads_header(fp);
2697 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002698
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002699 if (threads == NULL) {
2700 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2701 return 0;
2702 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002703
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002704 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002705 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2706
2707 resort_rb__delete(threads);
2708
2709 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002710}
2711
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002712static int trace__set_duration(const struct option *opt, const char *str,
2713 int unset __maybe_unused)
2714{
2715 struct trace *trace = opt->value;
2716
2717 trace->duration_filter = atof(str);
2718 return 0;
2719}
2720
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002721static int trace__set_filter_pids(const struct option *opt, const char *str,
2722 int unset __maybe_unused)
2723{
2724 int ret = -1;
2725 size_t i;
2726 struct trace *trace = opt->value;
2727 /*
2728 * FIXME: introduce a intarray class, plain parse csv and create a
2729 * { int nr, int entries[] } struct...
2730 */
2731 struct intlist *list = intlist__new(str);
2732
2733 if (list == NULL)
2734 return -1;
2735
2736 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2737 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2738
2739 if (trace->filter_pids.entries == NULL)
2740 goto out;
2741
2742 trace->filter_pids.entries[0] = getpid();
2743
2744 for (i = 1; i < trace->filter_pids.nr; ++i)
2745 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2746
2747 intlist__delete(list);
2748 ret = 0;
2749out:
2750 return ret;
2751}
2752
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002753static int trace__open_output(struct trace *trace, const char *filename)
2754{
2755 struct stat st;
2756
2757 if (!stat(filename, &st) && st.st_size) {
2758 char oldname[PATH_MAX];
2759
2760 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2761 unlink(oldname);
2762 rename(filename, oldname);
2763 }
2764
2765 trace->output = fopen(filename, "w");
2766
2767 return trace->output == NULL ? -errno : 0;
2768}
2769
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002770static int parse_pagefaults(const struct option *opt, const char *str,
2771 int unset __maybe_unused)
2772{
2773 int *trace_pgfaults = opt->value;
2774
2775 if (strcmp(str, "all") == 0)
2776 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2777 else if (strcmp(str, "maj") == 0)
2778 *trace_pgfaults |= TRACE_PFMAJ;
2779 else if (strcmp(str, "min") == 0)
2780 *trace_pgfaults |= TRACE_PFMIN;
2781 else
2782 return -1;
2783
2784 return 0;
2785}
2786
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002787static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2788{
2789 struct perf_evsel *evsel;
2790
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002791 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002792 evsel->handler = handler;
2793}
2794
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002795/*
2796 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2797 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2798 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2799 *
2800 * It'd be better to introduce a parse_options() variant that would return a
2801 * list with the terms it didn't match to an event...
2802 */
2803static int trace__parse_events_option(const struct option *opt, const char *str,
2804 int unset __maybe_unused)
2805{
2806 struct trace *trace = (struct trace *)opt->value;
2807 const char *s = str;
2808 char *sep = NULL, *lists[2] = { NULL, NULL, };
2809 int len = strlen(str), err = -1, list;
2810 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2811 char group_name[PATH_MAX];
2812
2813 if (strace_groups_dir == NULL)
2814 return -1;
2815
2816 if (*s == '!') {
2817 ++s;
2818 trace->not_ev_qualifier = true;
2819 }
2820
2821 while (1) {
2822 if ((sep = strchr(s, ',')) != NULL)
2823 *sep = '\0';
2824
2825 list = 0;
2826 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2827 list = 1;
2828 } else {
2829 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2830 if (access(group_name, R_OK) == 0)
2831 list = 1;
2832 }
2833
2834 if (lists[list]) {
2835 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2836 } else {
2837 lists[list] = malloc(len);
2838 if (lists[list] == NULL)
2839 goto out;
2840 strcpy(lists[list], s);
2841 }
2842
2843 if (!sep)
2844 break;
2845
2846 *sep = ',';
2847 s = sep + 1;
2848 }
2849
2850 if (lists[1] != NULL) {
2851 struct strlist_config slist_config = {
2852 .dirname = strace_groups_dir,
2853 };
2854
2855 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2856 if (trace->ev_qualifier == NULL) {
2857 fputs("Not enough memory to parse event qualifier", trace->output);
2858 goto out;
2859 }
2860
2861 if (trace__validate_ev_qualifier(trace))
2862 goto out;
2863 }
2864
2865 err = 0;
2866
2867 if (lists[0]) {
2868 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2869 "event selector. use 'perf list' to list available events",
2870 parse_events_option);
2871 err = parse_events_option(&o, lists[0], 0);
2872 }
2873out:
2874 if (sep)
2875 *sep = ',';
2876
2877 return err;
2878}
2879
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002880int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002881{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002882 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002883 "perf trace [<options>] [<command>]",
2884 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002885 "perf trace record [<options>] [<command>]",
2886 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002887 NULL
2888 };
2889 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002890 .syscalls = {
2891 . max = -1,
2892 },
2893 .opts = {
2894 .target = {
2895 .uid = UINT_MAX,
2896 .uses_mmap = true,
2897 },
2898 .user_freq = UINT_MAX,
2899 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002900 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002901 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002902 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002903 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002904 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002905 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002906 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002907 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002908 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002909 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002910 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002911 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002912 OPT_CALLBACK('e', "event", &trace, "event",
2913 "event/syscall selector. use 'perf list' to list available events",
2914 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002915 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2916 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002917 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002918 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2919 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002920 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002921 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002922 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2923 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002924 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002925 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002926 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2927 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002928 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002929 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002930 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002931 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002932 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002933 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002934 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2935 "number of mmap data pages",
2936 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002937 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002938 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002939 OPT_CALLBACK(0, "duration", &trace, "float",
2940 "show only events with duration > N.M ms",
2941 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002942 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002943 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002944 OPT_BOOLEAN('T', "time", &trace.full_time,
2945 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002946 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2947 "Show only syscall summary with statistics"),
2948 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2949 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002950 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2951 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002952 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002953 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002954 OPT_CALLBACK(0, "call-graph", &trace.opts,
2955 "record_mode[,record_size]", record_callchain_help,
2956 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002957 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2958 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002959 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2960 "Set the minimum stack depth when parsing the callchain, "
2961 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002962 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2963 "Set the maximum stack depth when parsing the callchain, "
2964 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002965 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002966 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2967 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002968 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2969 "ms to wait before starting measurement after program "
2970 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002971 OPT_END()
2972 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002973 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002974 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002975 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002976 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002977 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002978
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002979 signal(SIGSEGV, sighandler_dump_stack);
2980 signal(SIGFPE, sighandler_dump_stack);
2981
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002982 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002983 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002984
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002985 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002986 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002987 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002988 goto out;
2989 }
2990
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002991 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2992 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002993
Wang Nand7888572016-04-08 15:07:24 +00002994 err = bpf__setup_stdout(trace.evlist);
2995 if (err) {
2996 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2997 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2998 goto out;
2999 }
3000
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003001 err = -1;
3002
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003003 if (trace.trace_pgfaults) {
3004 trace.opts.sample_address = true;
3005 trace.opts.sample_time = true;
3006 }
3007
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003008 if (trace.opts.mmap_pages == UINT_MAX)
3009 mmap_pages_user_set = false;
3010
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003011 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003012 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003013 max_stack_user_set = false;
3014 }
3015
3016#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003017 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003018 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3019#endif
3020
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003021 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003022 if (!mmap_pages_user_set && geteuid() == 0)
3023 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3024
Milian Wolff566a0882016-04-08 13:34:15 +02003025 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003026 }
Milian Wolff566a0882016-04-08 13:34:15 +02003027
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003028 if (trace.evlist->nr_entries > 0)
3029 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3030
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003031 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3032 return trace__record(&trace, argc-1, &argv[1]);
3033
3034 /* summary_only implies summary option, but don't overwrite summary if set */
3035 if (trace.summary_only)
3036 trace.summary = trace.summary_only;
3037
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003038 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3039 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003040 pr_err("Please specify something to trace.\n");
3041 return -1;
3042 }
3043
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003044 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003045 pr_err("The -e option can't be used with --no-syscalls.\n");
3046 goto out;
3047 }
3048
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003049 if (output_name != NULL) {
3050 err = trace__open_output(&trace, output_name);
3051 if (err < 0) {
3052 perror("failed to create output file");
3053 goto out;
3054 }
3055 }
3056
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003057 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3058
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003059 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003060 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003061 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003062 fprintf(trace.output, "%s", bf);
3063 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003064 }
3065
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003066 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003067 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003068 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003069 fprintf(trace.output, "%s", bf);
3070 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003071 }
3072
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003073 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003074 trace.opts.target.system_wide = true;
3075
David Ahern6810fc92013-08-28 22:29:52 -06003076 if (input_name)
3077 err = trace__replay(&trace);
3078 else
3079 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003080
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003081out_close:
3082 if (output_name != NULL)
3083 fclose(trace.output);
3084out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003085 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003086}