blob: d5d7fff1c211ca809db3c6adce0420be0a34e929 [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 Melo83bc9c372017-08-28 11:47:11 -0300696 { .name = "pkey_alloc",
697 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
698 { .name = "pkey_free",
699 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
700 { .name = "pkey_mprotect",
701 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
702 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
703 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300704 { .name = "poll", .timeout = true, },
705 { .name = "ppoll", .timeout = true, },
706 { .name = "pread", .alias = "pread64", },
707 { .name = "preadv", .alias = "pread", },
708 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300709 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300710 { .name = "pwrite", .alias = "pwrite64", },
711 { .name = "readlinkat",
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 = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300717 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300718 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300719 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300720 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300721 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300722 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300723 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300724 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300726 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300727 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300728 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300730 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300731 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300732 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
733 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300734 { .name = "select", .timeout = true, },
735 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300736 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300737 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300738 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300739 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300740 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300741 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300745 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300746 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300747 .arg = { [0] = STRARRAY(family, socket_families),
748 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300750 .arg = { [0] = STRARRAY(family, socket_families),
751 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "stat", .alias = "newstat", },
753 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300754 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
755 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
756 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300757 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300758 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300759 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300760 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300761 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300762 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300763 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300764 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300765 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300766 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300767 { .name = "uname", .alias = "newuname", },
768 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300769 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300770 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300771 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300772 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300773 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300774 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300775 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300776};
777
778static int syscall_fmt__cmp(const void *name, const void *fmtp)
779{
780 const struct syscall_fmt *fmt = fmtp;
781 return strcmp(name, fmt->name);
782}
783
784static struct syscall_fmt *syscall_fmt__find(const char *name)
785{
786 const int nmemb = ARRAY_SIZE(syscall_fmts);
787 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
788}
789
790struct syscall {
791 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300792 int nr_args;
793 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300794 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300795 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300796 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300797 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300798};
799
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300800/*
801 * We need to have this 'calculated' boolean because in some cases we really
802 * don't know what is the duration of a syscall, for instance, when we start
803 * a session and some threads are waiting for a syscall to finish, say 'poll',
804 * in which case all we can do is to print "( ? ) for duration and for the
805 * start timestamp.
806 */
807static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200808{
809 double duration = (double)t / NSEC_PER_MSEC;
810 size_t printed = fprintf(fp, "(");
811
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300812 if (!calculated)
813 printed += fprintf(fp, " ? ");
814 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200815 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
816 else if (duration >= 0.01)
817 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
818 else
819 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300820 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200821}
822
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300823/**
824 * filename.ptr: The filename char pointer that will be vfs_getname'd
825 * filename.entry_str_pos: Where to insert the string translated from
826 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300827 * ret_scnprintf: syscall args may set this to a different syscall return
828 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300829 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300830struct thread_trace {
831 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300832 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300833 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400834 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300835 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300836 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300837 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300838 struct {
839 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300840 short int entry_str_pos;
841 bool pending_open;
842 unsigned int namelen;
843 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300844 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300845 struct {
846 int max;
847 char **table;
848 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600849
850 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300851};
852
853static struct thread_trace *thread_trace__new(void)
854{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300855 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
856
857 if (ttrace)
858 ttrace->paths.max = -1;
859
David Ahernbf2575c2013-10-08 21:26:53 -0600860 ttrace->syscall_stats = intlist__new(NULL);
861
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300862 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300863}
864
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300865static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300866{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300867 struct thread_trace *ttrace;
868
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300869 if (thread == NULL)
870 goto fail;
871
Namhyung Kim89dceb22014-10-06 09:46:03 +0900872 if (thread__priv(thread) == NULL)
873 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300874
Namhyung Kim89dceb22014-10-06 09:46:03 +0900875 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876 goto fail;
877
Namhyung Kim89dceb22014-10-06 09:46:03 +0900878 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300879 ++ttrace->nr_events;
880
881 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300882fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300883 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300884 "WARNING: not enough memory, dropping samples!\n");
885 return NULL;
886}
887
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300888
889void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300890 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300891{
892 struct thread_trace *ttrace = thread__priv(arg->thread);
893
894 ttrace->ret_scnprintf = ret_scnprintf;
895}
896
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400897#define TRACE_PFMAJ (1 << 0)
898#define TRACE_PFMIN (1 << 1)
899
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300900static const size_t trace__entry_str_size = 2048;
901
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300902static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300903{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900904 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300905
906 if (fd > ttrace->paths.max) {
907 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
908
909 if (npath == NULL)
910 return -1;
911
912 if (ttrace->paths.max != -1) {
913 memset(npath + ttrace->paths.max + 1, 0,
914 (fd - ttrace->paths.max) * sizeof(char *));
915 } else {
916 memset(npath, 0, (fd + 1) * sizeof(char *));
917 }
918
919 ttrace->paths.table = npath;
920 ttrace->paths.max = fd;
921 }
922
923 ttrace->paths.table[fd] = strdup(pathname);
924
925 return ttrace->paths.table[fd] != NULL ? 0 : -1;
926}
927
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300928static int thread__read_fd_path(struct thread *thread, int fd)
929{
930 char linkname[PATH_MAX], pathname[PATH_MAX];
931 struct stat st;
932 int ret;
933
934 if (thread->pid_ == thread->tid) {
935 scnprintf(linkname, sizeof(linkname),
936 "/proc/%d/fd/%d", thread->pid_, fd);
937 } else {
938 scnprintf(linkname, sizeof(linkname),
939 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
940 }
941
942 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
943 return -1;
944
945 ret = readlink(linkname, pathname, sizeof(pathname));
946
947 if (ret < 0 || ret > st.st_size)
948 return -1;
949
950 pathname[ret] = '\0';
951 return trace__set_fd_pathname(thread, fd, pathname);
952}
953
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300954static const char *thread__fd_path(struct thread *thread, int fd,
955 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300956{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900957 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300958
959 if (ttrace == NULL)
960 return NULL;
961
962 if (fd < 0)
963 return NULL;
964
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300965 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300966 if (!trace->live)
967 return NULL;
968 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300969 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300970 return NULL;
971 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300972
973 return ttrace->paths.table[fd];
974}
975
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -0300976size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977{
978 int fd = arg->val;
979 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300980 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300981
982 if (path)
983 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
984
985 return printed;
986}
987
988static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
989 struct syscall_arg *arg)
990{
991 int fd = arg->val;
992 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +0900993 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300995 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
996 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997
998 return printed;
999}
1000
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001001static void thread__set_filename_pos(struct thread *thread, const char *bf,
1002 unsigned long ptr)
1003{
1004 struct thread_trace *ttrace = thread__priv(thread);
1005
1006 ttrace->filename.ptr = ptr;
1007 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1008}
1009
1010static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1011 struct syscall_arg *arg)
1012{
1013 unsigned long ptr = arg->val;
1014
1015 if (!arg->trace->vfs_getname)
1016 return scnprintf(bf, size, "%#x", ptr);
1017
1018 thread__set_filename_pos(arg->thread, bf, ptr);
1019 return 0;
1020}
1021
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001022static bool trace__filter_duration(struct trace *trace, double t)
1023{
1024 return t < (trace->duration_filter * NSEC_PER_MSEC);
1025}
1026
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001027static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001028{
1029 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1030
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001031 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001032}
1033
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001034/*
1035 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1036 * using ttrace->entry_time for a thread that receives a sys_exit without
1037 * first having received a sys_enter ("poll" issued before tracing session
1038 * starts, lost sys_enter exit due to ring buffer overflow).
1039 */
1040static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1041{
1042 if (tstamp > 0)
1043 return __trace__fprintf_tstamp(trace, tstamp, fp);
1044
1045 return fprintf(fp, " ? ");
1046}
1047
Namhyung Kimf15eb532012-10-05 14:02:16 +09001048static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001049static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001050
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001051static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001052{
1053 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001054 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001055}
1056
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001057static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001058 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001059{
1060 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001061 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001062
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001063 if (trace->multiple_threads) {
1064 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001065 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001066 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001067 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001068
1069 return printed;
1070}
1071
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001072static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001073 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001074{
1075 int ret = 0;
1076
1077 switch (event->header.type) {
1078 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001079 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001080 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001081 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001082 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001083 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001084 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001085 break;
1086 }
1087
1088 return ret;
1089}
1090
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001091static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001092 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001093 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094 struct machine *machine)
1095{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001096 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001097 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098}
1099
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001100static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1101{
1102 struct machine *machine = vmachine;
1103
1104 if (machine->kptr_restrict_warned)
1105 return NULL;
1106
1107 if (symbol_conf.kptr_restrict) {
1108 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1109 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1110 "Kernel samples will not be resolved.\n");
1111 machine->kptr_restrict_warned = true;
1112 return NULL;
1113 }
1114
1115 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1116}
1117
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001118static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1119{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001120 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121
1122 if (err)
1123 return err;
1124
David Ahern8fb598e2013-09-28 13:13:00 -06001125 trace->host = machine__new_host();
1126 if (trace->host == NULL)
1127 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001129 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001130 return -errno;
1131
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001132 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001133 evlist->threads, trace__tool_process, false,
1134 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001135 if (err)
1136 symbol__exit();
1137
1138 return err;
1139}
1140
Andrei Vagin33974a42017-11-07 16:22:45 -08001141static void trace__symbols__exit(struct trace *trace)
1142{
1143 machine__exit(trace->host);
1144 trace->host = NULL;
1145
1146 symbol__exit();
1147}
1148
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001149static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1150{
1151 int idx;
1152
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001153 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1154 nr_args = sc->fmt->nr_args;
1155
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001156 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1157 if (sc->arg_fmt == NULL)
1158 return -1;
1159
1160 for (idx = 0; idx < nr_args; ++idx) {
1161 if (sc->fmt)
1162 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1163 }
1164
1165 sc->nr_args = nr_args;
1166 return 0;
1167}
1168
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001169static int syscall__set_arg_fmts(struct syscall *sc)
1170{
1171 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001172 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001173
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001174 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001175 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1176 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001177
1178 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001179 (strcmp(field->name, "filename") == 0 ||
1180 strcmp(field->name, "path") == 0 ||
1181 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001182 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001183 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001184 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001185 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001186 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001187 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001188 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001189 else if ((strcmp(field->type, "int") == 0 ||
1190 strcmp(field->type, "unsigned int") == 0 ||
1191 strcmp(field->type, "long") == 0) &&
1192 (len = strlen(field->name)) >= 2 &&
1193 strcmp(field->name + len - 2, "fd") == 0) {
1194 /*
1195 * /sys/kernel/tracing/events/syscalls/sys_enter*
1196 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1197 * 65 int
1198 * 23 unsigned int
1199 * 7 unsigned long
1200 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001201 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001202 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001203 }
1204
1205 return 0;
1206}
1207
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001208static int trace__read_syscall_info(struct trace *trace, int id)
1209{
1210 char tp_name[128];
1211 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001212 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001213
1214 if (name == NULL)
1215 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001216
1217 if (id > trace->syscalls.max) {
1218 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1219
1220 if (nsyscalls == NULL)
1221 return -1;
1222
1223 if (trace->syscalls.max != -1) {
1224 memset(nsyscalls + trace->syscalls.max + 1, 0,
1225 (id - trace->syscalls.max) * sizeof(*sc));
1226 } else {
1227 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1228 }
1229
1230 trace->syscalls.table = nsyscalls;
1231 trace->syscalls.max = id;
1232 }
1233
1234 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001235 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001236
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001237 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001238
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001239 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001240 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001241
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001242 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001243 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001244 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001245 }
1246
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001247 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1248 return -1;
1249
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001250 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001251 return -1;
1252
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001253 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001254 /*
1255 * We need to check and discard the first variable '__syscall_nr'
1256 * or 'nr' that mean the syscall number. It is needless here.
1257 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1258 */
1259 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001260 sc->args = sc->args->next;
1261 --sc->nr_args;
1262 }
1263
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001264 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1265
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001266 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001267}
1268
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001269static int trace__validate_ev_qualifier(struct trace *trace)
1270{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001271 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001272 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001273 struct str_node *pos;
1274
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001275 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1276 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1277 sizeof(trace->ev_qualifier_ids.entries[0]));
1278
1279 if (trace->ev_qualifier_ids.entries == NULL) {
1280 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1281 trace->output);
1282 err = -EINVAL;
1283 goto out;
1284 }
1285
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001286 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001287 i = 0;
1288
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001289 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001290 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001291 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001292
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001293 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001294 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1295 if (id >= 0)
1296 goto matches;
1297
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001298 if (err == 0) {
1299 fputs("Error:\tInvalid syscall ", trace->output);
1300 err = -EINVAL;
1301 } else {
1302 fputs(", ", trace->output);
1303 }
1304
1305 fputs(sc, trace->output);
1306 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001307matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001308 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001309 if (match_next == -1)
1310 continue;
1311
1312 while (1) {
1313 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1314 if (id < 0)
1315 break;
1316 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1317 void *entries;
1318
1319 nr_allocated += 8;
1320 entries = realloc(trace->ev_qualifier_ids.entries,
1321 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1322 if (entries == NULL) {
1323 err = -ENOMEM;
1324 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1325 goto out_free;
1326 }
1327 trace->ev_qualifier_ids.entries = entries;
1328 }
1329 trace->ev_qualifier_ids.nr++;
1330 trace->ev_qualifier_ids.entries[i++] = id;
1331 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001332 }
1333
1334 if (err < 0) {
1335 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1336 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001337out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001338 zfree(&trace->ev_qualifier_ids.entries);
1339 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001340 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001341out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001342 return err;
1343}
1344
David Ahern55d43bca2015-02-19 15:00:22 -05001345/*
1346 * args is to be interpreted as a series of longs but we need to handle
1347 * 8-byte unaligned accesses. args points to raw_data within the event
1348 * and raw_data is guaranteed to be 8-byte unaligned because it is
1349 * preceded by raw_size which is a u32. So we need to copy args to a temp
1350 * variable to read it. Most notably this avoids extended load instructions
1351 * on unaligned addresses
1352 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001353unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001354{
1355 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001356 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001357
1358 memcpy(&val, p, sizeof(val));
1359 return val;
1360}
1361
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001362static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1363 struct syscall_arg *arg)
1364{
1365 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1366 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1367
1368 return scnprintf(bf, size, "arg%d: ", arg->idx);
1369}
1370
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001371static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1372 struct syscall_arg *arg, unsigned long val)
1373{
1374 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1375 arg->val = val;
1376 if (sc->arg_fmt[arg->idx].parm)
1377 arg->parm = sc->arg_fmt[arg->idx].parm;
1378 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1379 }
1380 return scnprintf(bf, size, "%ld", val);
1381}
1382
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001383static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001384 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001385 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001387 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001388 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001389 u8 bit = 1;
1390 struct syscall_arg arg = {
1391 .args = args,
1392 .idx = 0,
1393 .mask = 0,
1394 .trace = trace,
1395 .thread = thread,
1396 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001397 struct thread_trace *ttrace = thread__priv(thread);
1398
1399 /*
1400 * Things like fcntl will set this in its 'cmd' formatter to pick the
1401 * right formatter for the return value (an fd? file flags?), which is
1402 * not needed for syscalls that always return a given type, say an fd.
1403 */
1404 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001405
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001406 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001407 struct format_field *field;
1408
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001409 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001410 field = field->next, ++arg.idx, bit <<= 1) {
1411 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001412 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001413
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001414 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001415
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001416 /*
1417 * Suppress this argument if its value is zero and
1418 * and we don't have a string associated in an
1419 * strarray for it.
1420 */
David Ahern55d43bca2015-02-19 15:00:22 -05001421 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001422 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001423 (sc->arg_fmt[arg.idx].show_zero ||
1424 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001425 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1426 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001427 continue;
1428
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001429 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001430 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001431 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001432 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001433 } else if (IS_ERR(sc->tp_format)) {
1434 /*
1435 * If we managed to read the tracepoint /format file, then we
1436 * may end up not having any args, like with gettid(), so only
1437 * print the raw args when we didn't manage to read it.
1438 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001439 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001440 if (arg.mask & bit)
1441 goto next_arg;
1442 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001443 if (printed)
1444 printed += scnprintf(bf + printed, size - printed, ", ");
1445 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001446 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1447next_arg:
1448 ++arg.idx;
1449 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001450 }
1451 }
1452
1453 return printed;
1454}
1455
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001456typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001457 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001458 struct perf_sample *sample);
1459
1460static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001461 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001462{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001463
1464 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001465
1466 /*
1467 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1468 * before that, leaving at a higher verbosity level till that is
1469 * explained. Reproduced with plain ftrace with:
1470 *
1471 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1472 * grep "NR -1 " /t/trace_pipe
1473 *
1474 * After generating some load on the machine.
1475 */
1476 if (verbose > 1) {
1477 static u64 n;
1478 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1479 id, perf_evsel__name(evsel), ++n);
1480 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001481 return NULL;
1482 }
1483
1484 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1485 trace__read_syscall_info(trace, id))
1486 goto out_cant_read;
1487
1488 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1489 goto out_cant_read;
1490
1491 return &trace->syscalls.table[id];
1492
1493out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001494 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001495 fprintf(trace->output, "Problems reading syscall %d", id);
1496 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1497 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1498 fputs(" information\n", trace->output);
1499 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001500 return NULL;
1501}
1502
David Ahernbf2575c2013-10-08 21:26:53 -06001503static void thread__update_stats(struct thread_trace *ttrace,
1504 int id, struct perf_sample *sample)
1505{
1506 struct int_node *inode;
1507 struct stats *stats;
1508 u64 duration = 0;
1509
1510 inode = intlist__findnew(ttrace->syscall_stats, id);
1511 if (inode == NULL)
1512 return;
1513
1514 stats = inode->priv;
1515 if (stats == NULL) {
1516 stats = malloc(sizeof(struct stats));
1517 if (stats == NULL)
1518 return;
1519 init_stats(stats);
1520 inode->priv = stats;
1521 }
1522
1523 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1524 duration = sample->time - ttrace->entry_time;
1525
1526 update_stats(stats, duration);
1527}
1528
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001529static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1530{
1531 struct thread_trace *ttrace;
1532 u64 duration;
1533 size_t printed;
1534
1535 if (trace->current == NULL)
1536 return 0;
1537
1538 ttrace = thread__priv(trace->current);
1539
1540 if (!ttrace->entry_pending)
1541 return 0;
1542
1543 duration = sample->time - ttrace->entry_time;
1544
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001545 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001546 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1547 ttrace->entry_pending = false;
1548
1549 return printed;
1550}
1551
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001552static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001553 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001554 struct perf_sample *sample)
1555{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001556 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001557 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001558 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001559 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001560 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001561 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001562 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001563
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001564 if (sc == NULL)
1565 return -1;
1566
David Ahern8fb598e2013-09-28 13:13:00 -06001567 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001568 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001569 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001570 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001571
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001572 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001573
1574 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001575 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001576 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001577 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001578 }
1579
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001580 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001581 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001582
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001583 ttrace->entry_time = sample->time;
1584 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001585 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001586
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001587 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001588 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001589
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001590 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001591 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001592 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001593 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001594 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001595 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001596 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001597 /* See trace__vfs_getname & trace__sys_exit */
1598 ttrace->filename.pending_open = false;
1599 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001600
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001601 if (trace->current != thread) {
1602 thread__put(trace->current);
1603 trace->current = thread__get(thread);
1604 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001605 err = 0;
1606out_put:
1607 thread__put(thread);
1608 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001609}
1610
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001611static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1612 struct perf_sample *sample,
1613 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001614{
1615 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001616
1617 if (machine__resolve(trace->host, &al, sample) < 0 ||
1618 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1619 return -1;
1620
1621 return 0;
1622}
1623
1624static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1625{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001626 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001627 const unsigned int print_opts = EVSEL__PRINT_SYM |
1628 EVSEL__PRINT_DSO |
1629 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001630
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001631 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001632}
1633
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001634static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001635 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001636 struct perf_sample *sample)
1637{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001638 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001639 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001640 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001641 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001642 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001643 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001644 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001645
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001646 if (sc == NULL)
1647 return -1;
1648
David Ahern8fb598e2013-09-28 13:13:00 -06001649 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001650 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001651 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001652 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001653
David Ahernbf2575c2013-10-08 21:26:53 -06001654 if (trace->summary)
1655 thread__update_stats(ttrace, id, sample);
1656
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001657 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001658
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001659 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001660 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1661 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001662 ++trace->stats.vfs_getname;
1663 }
1664
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001665 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001666 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001667 if (trace__filter_duration(trace, duration))
1668 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001669 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001670 } else if (trace->duration_filter)
1671 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001672
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001673 if (sample->callchain) {
1674 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1675 if (callchain_ret == 0) {
1676 if (callchain_cursor.nr < trace->min_stack)
1677 goto out;
1678 callchain_ret = 1;
1679 }
1680 }
1681
David Ahernfd2eaba2013-11-12 09:31:15 -07001682 if (trace->summary_only)
1683 goto out;
1684
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001685 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001686
1687 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001688 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001689 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001690 fprintf(trace->output, " ... [");
1691 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1692 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001693 }
1694
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001695 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001696 if (ret < 0)
1697 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001698signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001699 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001700 } else if (ret < 0) {
1701errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001702 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001703 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001704 *e = audit_errno_to_name(-ret);
1705
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001706 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001707 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001708 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001709 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001710 else if (ttrace->ret_scnprintf) {
1711 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001712 struct syscall_arg arg = {
1713 .val = ret,
1714 .thread = thread,
1715 .trace = trace,
1716 };
1717 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001718 ttrace->ret_scnprintf = NULL;
1719 fprintf(trace->output, ") = %s", bf);
1720 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001721 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001722 else if (sc->fmt->errpid) {
1723 struct thread *child = machine__find_thread(trace->host, ret, ret);
1724
1725 if (child != NULL) {
1726 fprintf(trace->output, ") = %ld", ret);
1727 if (child->comm_set)
1728 fprintf(trace->output, " (%s)", thread__comm_str(child));
1729 thread__put(child);
1730 }
1731 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001732 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001733
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001734 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001735
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001736 if (callchain_ret > 0)
1737 trace__fprintf_callchain(trace, sample);
1738 else if (callchain_ret < 0)
1739 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001740out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001741 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001742 err = 0;
1743out_put:
1744 thread__put(thread);
1745 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001746}
1747
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001748static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001749 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001750 struct perf_sample *sample)
1751{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001752 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1753 struct thread_trace *ttrace;
1754 size_t filename_len, entry_str_len, to_move;
1755 ssize_t remaining_space;
1756 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001757 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001758
1759 if (!thread)
1760 goto out;
1761
1762 ttrace = thread__priv(thread);
1763 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001764 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001765
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001766 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001767 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001768 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001769
1770 if (ttrace->filename.namelen < filename_len) {
1771 char *f = realloc(ttrace->filename.name, filename_len + 1);
1772
1773 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001774 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001775
1776 ttrace->filename.namelen = filename_len;
1777 ttrace->filename.name = f;
1778 }
1779
1780 strcpy(ttrace->filename.name, filename);
1781 ttrace->filename.pending_open = true;
1782
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001783 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001784 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001785
1786 entry_str_len = strlen(ttrace->entry_str);
1787 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1788 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001789 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001790
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001791 if (filename_len > (size_t)remaining_space) {
1792 filename += filename_len - remaining_space;
1793 filename_len = remaining_space;
1794 }
1795
1796 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1797 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1798 memmove(pos + filename_len, pos, to_move);
1799 memcpy(pos, filename, filename_len);
1800
1801 ttrace->filename.ptr = 0;
1802 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001803out_put:
1804 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001805out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001806 return 0;
1807}
1808
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001809static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001810 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001811 struct perf_sample *sample)
1812{
1813 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1814 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001815 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001816 sample->pid,
1817 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001818 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001819
1820 if (ttrace == NULL)
1821 goto out_dump;
1822
1823 ttrace->runtime_ms += runtime_ms;
1824 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001825out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001826 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001827 return 0;
1828
1829out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001830 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001831 evsel->name,
1832 perf_evsel__strval(evsel, sample, "comm"),
1833 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1834 runtime,
1835 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001836 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001837}
1838
Wang Nan1d6c9402016-02-26 09:31:55 +00001839static void bpf_output__printer(enum binary_printer_ops op,
1840 unsigned int val, void *extra)
1841{
1842 FILE *output = extra;
1843 unsigned char ch = (unsigned char)val;
1844
1845 switch (op) {
1846 case BINARY_PRINT_CHAR_DATA:
1847 fprintf(output, "%c", isprint(ch) ? ch : '.');
1848 break;
1849 case BINARY_PRINT_DATA_BEGIN:
1850 case BINARY_PRINT_LINE_BEGIN:
1851 case BINARY_PRINT_ADDR:
1852 case BINARY_PRINT_NUM_DATA:
1853 case BINARY_PRINT_NUM_PAD:
1854 case BINARY_PRINT_SEP:
1855 case BINARY_PRINT_CHAR_PAD:
1856 case BINARY_PRINT_LINE_END:
1857 case BINARY_PRINT_DATA_END:
1858 default:
1859 break;
1860 }
1861}
1862
1863static void bpf_output__fprintf(struct trace *trace,
1864 struct perf_sample *sample)
1865{
1866 print_binary(sample->raw_data, sample->raw_size, 8,
1867 bpf_output__printer, trace->output);
1868}
1869
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001870static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1871 union perf_event *event __maybe_unused,
1872 struct perf_sample *sample)
1873{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001874 int callchain_ret = 0;
1875
1876 if (sample->callchain) {
1877 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1878 if (callchain_ret == 0) {
1879 if (callchain_cursor.nr < trace->min_stack)
1880 goto out;
1881 callchain_ret = 1;
1882 }
1883 }
1884
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001885 trace__printf_interrupted_entry(trace, sample);
1886 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001887
1888 if (trace->trace_syscalls)
1889 fprintf(trace->output, "( ): ");
1890
1891 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001892
Wang Nan1d6c9402016-02-26 09:31:55 +00001893 if (perf_evsel__is_bpf_output(evsel)) {
1894 bpf_output__fprintf(trace, sample);
1895 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001896 event_format__fprintf(evsel->tp_format, sample->cpu,
1897 sample->raw_data, sample->raw_size,
1898 trace->output);
1899 }
1900
1901 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001902
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001903 if (callchain_ret > 0)
1904 trace__fprintf_callchain(trace, sample);
1905 else if (callchain_ret < 0)
1906 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1907out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001908 return 0;
1909}
1910
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001911static void print_location(FILE *f, struct perf_sample *sample,
1912 struct addr_location *al,
1913 bool print_dso, bool print_sym)
1914{
1915
Namhyung Kimbb963e12017-02-17 17:17:38 +09001916 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001917 fprintf(f, "%s@", al->map->dso->long_name);
1918
Namhyung Kimbb963e12017-02-17 17:17:38 +09001919 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001920 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001921 al->addr - al->sym->start);
1922 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001923 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001924 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001925 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001926}
1927
1928static int trace__pgfault(struct trace *trace,
1929 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001930 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001931 struct perf_sample *sample)
1932{
1933 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001934 struct addr_location al;
1935 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001936 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001937 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001938 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001939
1940 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001941
1942 if (sample->callchain) {
1943 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1944 if (callchain_ret == 0) {
1945 if (callchain_cursor.nr < trace->min_stack)
1946 goto out_put;
1947 callchain_ret = 1;
1948 }
1949 }
1950
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001951 ttrace = thread__trace(thread, trace->output);
1952 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001953 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001954
1955 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1956 ttrace->pfmaj++;
1957 else
1958 ttrace->pfmin++;
1959
1960 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001961 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001962
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001963 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001964 sample->ip, &al);
1965
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001966 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001967
1968 fprintf(trace->output, "%sfault [",
1969 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1970 "maj" : "min");
1971
1972 print_location(trace->output, sample, &al, false, true);
1973
1974 fprintf(trace->output, "] => ");
1975
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001976 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001977 sample->addr, &al);
1978
1979 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001980 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001981 MAP__FUNCTION, sample->addr, &al);
1982
1983 if (al.map)
1984 map_type = 'x';
1985 else
1986 map_type = '?';
1987 }
1988
1989 print_location(trace->output, sample, &al, true, false);
1990
1991 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001992
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001993 if (callchain_ret > 0)
1994 trace__fprintf_callchain(trace, sample);
1995 else if (callchain_ret < 0)
1996 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001997out:
1998 err = 0;
1999out_put:
2000 thread__put(thread);
2001 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002002}
2003
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002004static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002005 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002006 struct perf_sample *sample)
2007{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002008 /*
2009 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2010 * and don't use sample->time unconditionally, we may end up having
2011 * some other event in the future without PERF_SAMPLE_TIME for good
2012 * reason, i.e. we may not be interested in its timestamps, just in
2013 * it taking place, picking some piece of information when it
2014 * appears in our event stream (vfs_getname comes to mind).
2015 */
2016 if (trace->base_time == 0 && !trace->full_time &&
2017 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002018 trace->base_time = sample->time;
2019}
2020
David Ahern6810fc92013-08-28 22:29:52 -06002021static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002022 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002023 struct perf_sample *sample,
2024 struct perf_evsel *evsel,
2025 struct machine *machine __maybe_unused)
2026{
2027 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002028 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002029 int err = 0;
2030
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002031 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002032
David Ahernaa07df62016-11-25 09:29:52 -07002033 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2034 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002035 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002036
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002037 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002038
David Ahern31605652013-12-04 19:41:41 -07002039 if (handler) {
2040 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002041 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002042 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002043out:
2044 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002045 return err;
2046}
2047
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002048static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002049{
2050 unsigned int rec_argc, i, j;
2051 const char **rec_argv;
2052 const char * const record_args[] = {
2053 "record",
2054 "-R",
2055 "-m", "1024",
2056 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002057 };
2058
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002059 const char * const sc_args[] = { "-e", };
2060 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2061 const char * const majpf_args[] = { "-e", "major-faults" };
2062 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2063 const char * const minpf_args[] = { "-e", "minor-faults" };
2064 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2065
David Ahern9aca7f12013-12-04 19:41:39 -07002066 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002067 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2068 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002069 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2070
2071 if (rec_argv == NULL)
2072 return -ENOMEM;
2073
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002074 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002075 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002076 rec_argv[j++] = record_args[i];
2077
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002078 if (trace->trace_syscalls) {
2079 for (i = 0; i < sc_args_nr; i++)
2080 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002081
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002082 /* event string may be different for older kernels - e.g., RHEL6 */
2083 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2084 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2085 else if (is_valid_tracepoint("syscalls:sys_enter"))
2086 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2087 else {
2088 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2089 return -1;
2090 }
David Ahern9aca7f12013-12-04 19:41:39 -07002091 }
David Ahern9aca7f12013-12-04 19:41:39 -07002092
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002093 if (trace->trace_pgfaults & TRACE_PFMAJ)
2094 for (i = 0; i < majpf_args_nr; i++)
2095 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002096
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002097 if (trace->trace_pgfaults & TRACE_PFMIN)
2098 for (i = 0; i < minpf_args_nr; i++)
2099 rec_argv[j++] = minpf_args[i];
2100
2101 for (i = 0; i < (unsigned int)argc; i++)
2102 rec_argv[j++] = argv[i];
2103
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002104 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002105}
2106
David Ahernbf2575c2013-10-08 21:26:53 -06002107static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2108
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002109static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002110{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002111 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002112
2113 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002114 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002115
2116 if (perf_evsel__field(evsel, "pathname") == NULL) {
2117 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002118 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002119 }
2120
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002121 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002122 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002123 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002124}
2125
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002126static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002127{
2128 struct perf_evsel *evsel;
2129 struct perf_event_attr attr = {
2130 .type = PERF_TYPE_SOFTWARE,
2131 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002132 };
2133
2134 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002135 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002136
2137 event_attr_init(&attr);
2138
2139 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002140 if (evsel)
2141 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002142
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002143 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002144}
2145
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002146static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2147{
2148 const u32 type = event->header.type;
2149 struct perf_evsel *evsel;
2150
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002151 if (type != PERF_RECORD_SAMPLE) {
2152 trace__process_event(trace, trace->host, event, sample);
2153 return;
2154 }
2155
2156 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2157 if (evsel == NULL) {
2158 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2159 return;
2160 }
2161
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002162 trace__set_base_time(trace, evsel, sample);
2163
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002164 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2165 sample->raw_data == NULL) {
2166 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2167 perf_evsel__name(evsel), sample->tid,
2168 sample->cpu, sample->raw_size);
2169 } else {
2170 tracepoint_handler handler = evsel->handler;
2171 handler(trace, evsel, event, sample);
2172 }
2173}
2174
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002175static int trace__add_syscall_newtp(struct trace *trace)
2176{
2177 int ret = -1;
2178 struct perf_evlist *evlist = trace->evlist;
2179 struct perf_evsel *sys_enter, *sys_exit;
2180
2181 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2182 if (sys_enter == NULL)
2183 goto out;
2184
2185 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2186 goto out_delete_sys_enter;
2187
2188 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2189 if (sys_exit == NULL)
2190 goto out_delete_sys_enter;
2191
2192 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2193 goto out_delete_sys_exit;
2194
2195 perf_evlist__add(evlist, sys_enter);
2196 perf_evlist__add(evlist, sys_exit);
2197
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002198 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002199 /*
2200 * We're interested only in the user space callchain
2201 * leading to the syscall, allow overriding that for
2202 * debugging reasons using --kernel_syscall_callchains
2203 */
2204 sys_exit->attr.exclude_callchain_kernel = 1;
2205 }
2206
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002207 trace->syscalls.events.sys_enter = sys_enter;
2208 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002209
2210 ret = 0;
2211out:
2212 return ret;
2213
2214out_delete_sys_exit:
2215 perf_evsel__delete_priv(sys_exit);
2216out_delete_sys_enter:
2217 perf_evsel__delete_priv(sys_enter);
2218 goto out;
2219}
2220
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002221static int trace__set_ev_qualifier_filter(struct trace *trace)
2222{
2223 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002224 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002225 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2226 trace->ev_qualifier_ids.nr,
2227 trace->ev_qualifier_ids.entries);
2228
2229 if (filter == NULL)
2230 goto out_enomem;
2231
Mathieu Poirier3541c032016-09-16 08:44:04 -06002232 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2233 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002234 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002235 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002236 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002237
2238 free(filter);
2239out:
2240 return err;
2241out_enomem:
2242 errno = ENOMEM;
2243 goto out;
2244}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002245
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002246static int trace__set_filter_loop_pids(struct trace *trace)
2247{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002248 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002249 pid_t pids[32] = {
2250 getpid(),
2251 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002252 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2253
2254 while (thread && nr < ARRAY_SIZE(pids)) {
2255 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2256
2257 if (parent == NULL)
2258 break;
2259
2260 if (!strcmp(thread__comm_str(parent), "sshd")) {
2261 pids[nr++] = parent->tid;
2262 break;
2263 }
2264 thread = parent;
2265 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002266
2267 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2268}
2269
Namhyung Kimf15eb532012-10-05 14:02:16 +09002270static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002271{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002272 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002273 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002274 int err = -1, i;
2275 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002276 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002277 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002278
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002279 trace->live = true;
2280
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002281 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002282 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002283
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002284 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002285 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002286
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002287 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2288 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2289 if (pgfault_maj == NULL)
2290 goto out_error_mem;
2291 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002292 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002293
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002294 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2295 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2296 if (pgfault_min == NULL)
2297 goto out_error_mem;
2298 perf_evlist__add(evlist, pgfault_min);
2299 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002300
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002301 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002302 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2303 trace__sched_stat_runtime))
2304 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002305
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002306 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2307 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002308 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002309 goto out_delete_evlist;
2310 }
2311
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002312 err = trace__symbols_init(trace, evlist);
2313 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002314 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002315 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002316 }
2317
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002318 perf_evlist__config(evlist, &trace->opts, NULL);
2319
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002320 if (callchain_param.enabled) {
2321 bool use_identifier = false;
2322
2323 if (trace->syscalls.events.sys_exit) {
2324 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2325 &trace->opts, &callchain_param);
2326 use_identifier = true;
2327 }
2328
2329 if (pgfault_maj) {
2330 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2331 use_identifier = true;
2332 }
2333
2334 if (pgfault_min) {
2335 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2336 use_identifier = true;
2337 }
2338
2339 if (use_identifier) {
2340 /*
2341 * Now we have evsels with different sample_ids, use
2342 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2343 * from a fixed position in each ring buffer record.
2344 *
2345 * As of this the changeset introducing this comment, this
2346 * isn't strictly needed, as the fields that can come before
2347 * PERF_SAMPLE_ID are all used, but we'll probably disable
2348 * some of those for things like copying the payload of
2349 * pointer syscall arguments, and for vfs_getname we don't
2350 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2351 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2352 */
2353 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2354 perf_evlist__reset_sample_bit(evlist, ID);
2355 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002356 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002357
Namhyung Kimf15eb532012-10-05 14:02:16 +09002358 signal(SIGCHLD, sig_handler);
2359 signal(SIGINT, sig_handler);
2360
2361 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002362 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002363 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002364 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002365 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002366 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002367 }
2368 }
2369
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002370 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002371 if (err < 0)
2372 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002373
Wang Nanba504232016-02-26 09:31:54 +00002374 err = bpf__apply_obj_config();
2375 if (err) {
2376 char errbuf[BUFSIZ];
2377
2378 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2379 pr_err("ERROR: Apply config to BPF failed: %s\n",
2380 errbuf);
2381 goto out_error_open;
2382 }
2383
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002384 /*
2385 * Better not use !target__has_task() here because we need to cover the
2386 * case where no threads were specified in the command line, but a
2387 * workload was, and in that case we will fill in the thread_map when
2388 * we fork the workload in perf_evlist__prepare_workload.
2389 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002390 if (trace->filter_pids.nr > 0)
2391 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002392 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002393 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002394
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002395 if (err < 0)
2396 goto out_error_mem;
2397
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002398 if (trace->ev_qualifier_ids.nr > 0) {
2399 err = trace__set_ev_qualifier_filter(trace);
2400 if (err < 0)
2401 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002402
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002403 pr_debug("event qualifier tracepoint filter: %s\n",
2404 trace->syscalls.events.sys_exit->filter);
2405 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002406
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002407 err = perf_evlist__apply_filters(evlist, &evsel);
2408 if (err < 0)
2409 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002410
Jiri Olsaf8850372013-11-28 17:57:22 +01002411 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002412 if (err < 0)
2413 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002414
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002415 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002416 perf_evlist__enable(evlist);
2417
Namhyung Kimf15eb532012-10-05 14:02:16 +09002418 if (forks)
2419 perf_evlist__start_workload(evlist);
2420
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002421 if (trace->opts.initial_delay) {
2422 usleep(trace->opts.initial_delay * 1000);
2423 perf_evlist__enable(evlist);
2424 }
2425
Jiri Olsae13798c2015-06-23 00:36:02 +02002426 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002427 evlist->threads->nr > 1 ||
2428 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002430 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002431
2432 for (i = 0; i < evlist->nr_mmaps; i++) {
2433 union perf_event *event;
2434
2435 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002436 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002437
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002438 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002439
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002440 err = perf_evlist__parse_sample(evlist, event, &sample);
2441 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002442 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002443 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002444 }
2445
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002446 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002447next_event:
2448 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002449
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002450 if (interrupted)
2451 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002452
2453 if (done && !draining) {
2454 perf_evlist__disable(evlist);
2455 draining = true;
2456 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002457 }
2458 }
2459
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002460 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002461 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002462
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002463 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2464 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2465 draining = true;
2466
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002467 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002468 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002469 } else {
2470 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002471 }
2472
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002473out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002474 thread__zput(trace->current);
2475
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002476 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002478 if (!err) {
2479 if (trace->summary)
2480 trace__fprintf_thread_summary(trace, trace->output);
2481
2482 if (trace->show_tool_stats) {
2483 fprintf(trace->output, "Stats:\n "
2484 " vfs_getname : %" PRIu64 "\n"
2485 " proc_getname: %" PRIu64 "\n",
2486 trace->stats.vfs_getname,
2487 trace->stats.proc_getname);
2488 }
2489 }
David Ahernbf2575c2013-10-08 21:26:53 -06002490
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002491out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002492 trace__symbols__exit(trace);
2493
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002494 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002495 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002496 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002497 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002498{
2499 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002500
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002501out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002502 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002503 goto out_error;
2504
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002505out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002506 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002507 goto out_error;
2508
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002509out_error_mmap:
2510 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2511 goto out_error;
2512
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002513out_error_open:
2514 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2515
2516out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002517 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302518 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002519
2520out_error_apply_filters:
2521 fprintf(trace->output,
2522 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2523 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002524 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002525 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002526}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002527out_error_mem:
2528 fprintf(trace->output, "Not enough memory to run!\n");
2529 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002530
2531out_errno:
2532 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2533 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002534}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002535
David Ahern6810fc92013-08-28 22:29:52 -06002536static int trace__replay(struct trace *trace)
2537{
2538 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002539 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002540 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002541 struct perf_data_file file = {
2542 .path = input_name,
2543 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002544 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002545 };
David Ahern6810fc92013-08-28 22:29:52 -06002546 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002547 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002548 int err = -1;
2549
2550 trace->tool.sample = trace__process_sample;
2551 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002552 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002553 trace->tool.comm = perf_event__process_comm;
2554 trace->tool.exit = perf_event__process_exit;
2555 trace->tool.fork = perf_event__process_fork;
2556 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302557 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002558 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302559 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002560
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002561 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002562 trace->tool.ordering_requires_timestamps = true;
2563
2564 /* add tid to output */
2565 trace->multiple_threads = true;
2566
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002567 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002568 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002569 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002570
David Ahernaa07df62016-11-25 09:29:52 -07002571 if (trace->opts.target.pid)
2572 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2573
2574 if (trace->opts.target.tid)
2575 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2576
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002577 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002578 goto out;
2579
David Ahern8fb598e2013-09-28 13:13:00 -06002580 trace->host = &session->machines.host;
2581
David Ahern6810fc92013-08-28 22:29:52 -06002582 err = perf_session__set_tracepoints_handlers(session, handlers);
2583 if (err)
2584 goto out;
2585
Namhyung Kim003824e2013-11-12 15:25:00 +09002586 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2587 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002588 /* older kernels have syscalls tp versus raw_syscalls */
2589 if (evsel == NULL)
2590 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2591 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002592
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002593 if (evsel &&
2594 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2595 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002596 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2597 goto out;
2598 }
2599
2600 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2601 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002602 if (evsel == NULL)
2603 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2604 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002605 if (evsel &&
2606 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2607 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002608 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002609 goto out;
2610 }
2611
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002612 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002613 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2614 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2615 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2616 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2617 evsel->handler = trace__pgfault;
2618 }
2619
David Ahern6810fc92013-08-28 22:29:52 -06002620 setup_pager();
2621
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002622 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002623 if (err)
2624 pr_err("Failed to process events, error %d", err);
2625
David Ahernbf2575c2013-10-08 21:26:53 -06002626 else if (trace->summary)
2627 trace__fprintf_thread_summary(trace, trace->output);
2628
David Ahern6810fc92013-08-28 22:29:52 -06002629out:
2630 perf_session__delete(session);
2631
2632 return err;
2633}
2634
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002635static size_t trace__fprintf_threads_header(FILE *fp)
2636{
2637 size_t printed;
2638
Pekka Enberg99ff7152013-11-12 16:42:14 +02002639 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002640
2641 return printed;
2642}
2643
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002644DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2645 struct stats *stats;
2646 double msecs;
2647 int syscall;
2648)
2649{
2650 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2651 struct stats *stats = source->priv;
2652
2653 entry->syscall = source->i;
2654 entry->stats = stats;
2655 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2656}
2657
David Ahernbf2575c2013-10-08 21:26:53 -06002658static size_t thread__dump_stats(struct thread_trace *ttrace,
2659 struct trace *trace, FILE *fp)
2660{
David Ahernbf2575c2013-10-08 21:26:53 -06002661 size_t printed = 0;
2662 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002663 struct rb_node *nd;
2664 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002665
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002666 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002667 return 0;
2668
2669 printed += fprintf(fp, "\n");
2670
Milian Wolff834fd462015-08-06 11:24:29 +02002671 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2672 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2673 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002674
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002675 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002676 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002677 if (stats) {
2678 double min = (double)(stats->min) / NSEC_PER_MSEC;
2679 double max = (double)(stats->max) / NSEC_PER_MSEC;
2680 double avg = avg_stats(stats);
2681 double pct;
2682 u64 n = (u64) stats->n;
2683
2684 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2685 avg /= NSEC_PER_MSEC;
2686
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002687 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002688 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002689 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002690 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002691 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002692 }
David Ahernbf2575c2013-10-08 21:26:53 -06002693 }
2694
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002695 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002696 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002697
2698 return printed;
2699}
2700
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002701static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002702{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002703 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002704 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002705 double ratio;
2706
2707 if (ttrace == NULL)
2708 return 0;
2709
2710 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2711
Pekka Enberg15e65c62013-11-14 18:43:30 +02002712 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002713 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002714 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002715 if (ttrace->pfmaj)
2716 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2717 if (ttrace->pfmin)
2718 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002719 if (trace->sched)
2720 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2721 else if (fputc('\n', fp) != EOF)
2722 ++printed;
2723
David Ahernbf2575c2013-10-08 21:26:53 -06002724 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002725
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002726 return printed;
2727}
David Ahern896cbb52013-09-28 13:12:59 -06002728
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002729static unsigned long thread__nr_events(struct thread_trace *ttrace)
2730{
2731 return ttrace ? ttrace->nr_events : 0;
2732}
2733
2734DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2735 struct thread *thread;
2736)
2737{
2738 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002739}
2740
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002741static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2742{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002743 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2744 size_t printed = trace__fprintf_threads_header(fp);
2745 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002746
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002747 if (threads == NULL) {
2748 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2749 return 0;
2750 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002751
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002752 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002753 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2754
2755 resort_rb__delete(threads);
2756
2757 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002758}
2759
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002760static int trace__set_duration(const struct option *opt, const char *str,
2761 int unset __maybe_unused)
2762{
2763 struct trace *trace = opt->value;
2764
2765 trace->duration_filter = atof(str);
2766 return 0;
2767}
2768
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002769static int trace__set_filter_pids(const struct option *opt, const char *str,
2770 int unset __maybe_unused)
2771{
2772 int ret = -1;
2773 size_t i;
2774 struct trace *trace = opt->value;
2775 /*
2776 * FIXME: introduce a intarray class, plain parse csv and create a
2777 * { int nr, int entries[] } struct...
2778 */
2779 struct intlist *list = intlist__new(str);
2780
2781 if (list == NULL)
2782 return -1;
2783
2784 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2785 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2786
2787 if (trace->filter_pids.entries == NULL)
2788 goto out;
2789
2790 trace->filter_pids.entries[0] = getpid();
2791
2792 for (i = 1; i < trace->filter_pids.nr; ++i)
2793 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2794
2795 intlist__delete(list);
2796 ret = 0;
2797out:
2798 return ret;
2799}
2800
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002801static int trace__open_output(struct trace *trace, const char *filename)
2802{
2803 struct stat st;
2804
2805 if (!stat(filename, &st) && st.st_size) {
2806 char oldname[PATH_MAX];
2807
2808 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2809 unlink(oldname);
2810 rename(filename, oldname);
2811 }
2812
2813 trace->output = fopen(filename, "w");
2814
2815 return trace->output == NULL ? -errno : 0;
2816}
2817
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002818static int parse_pagefaults(const struct option *opt, const char *str,
2819 int unset __maybe_unused)
2820{
2821 int *trace_pgfaults = opt->value;
2822
2823 if (strcmp(str, "all") == 0)
2824 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2825 else if (strcmp(str, "maj") == 0)
2826 *trace_pgfaults |= TRACE_PFMAJ;
2827 else if (strcmp(str, "min") == 0)
2828 *trace_pgfaults |= TRACE_PFMIN;
2829 else
2830 return -1;
2831
2832 return 0;
2833}
2834
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002835static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2836{
2837 struct perf_evsel *evsel;
2838
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002839 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002840 evsel->handler = handler;
2841}
2842
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002843/*
2844 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2845 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2846 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2847 *
2848 * It'd be better to introduce a parse_options() variant that would return a
2849 * list with the terms it didn't match to an event...
2850 */
2851static int trace__parse_events_option(const struct option *opt, const char *str,
2852 int unset __maybe_unused)
2853{
2854 struct trace *trace = (struct trace *)opt->value;
2855 const char *s = str;
2856 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002857 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002858 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2859 char group_name[PATH_MAX];
2860
2861 if (strace_groups_dir == NULL)
2862 return -1;
2863
2864 if (*s == '!') {
2865 ++s;
2866 trace->not_ev_qualifier = true;
2867 }
2868
2869 while (1) {
2870 if ((sep = strchr(s, ',')) != NULL)
2871 *sep = '\0';
2872
2873 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002874 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
2875 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002876 list = 1;
2877 } else {
2878 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2879 if (access(group_name, R_OK) == 0)
2880 list = 1;
2881 }
2882
2883 if (lists[list]) {
2884 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2885 } else {
2886 lists[list] = malloc(len);
2887 if (lists[list] == NULL)
2888 goto out;
2889 strcpy(lists[list], s);
2890 }
2891
2892 if (!sep)
2893 break;
2894
2895 *sep = ',';
2896 s = sep + 1;
2897 }
2898
2899 if (lists[1] != NULL) {
2900 struct strlist_config slist_config = {
2901 .dirname = strace_groups_dir,
2902 };
2903
2904 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2905 if (trace->ev_qualifier == NULL) {
2906 fputs("Not enough memory to parse event qualifier", trace->output);
2907 goto out;
2908 }
2909
2910 if (trace__validate_ev_qualifier(trace))
2911 goto out;
2912 }
2913
2914 err = 0;
2915
2916 if (lists[0]) {
2917 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2918 "event selector. use 'perf list' to list available events",
2919 parse_events_option);
2920 err = parse_events_option(&o, lists[0], 0);
2921 }
2922out:
2923 if (sep)
2924 *sep = ',';
2925
2926 return err;
2927}
2928
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002929int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002930{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002931 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002932 "perf trace [<options>] [<command>]",
2933 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002934 "perf trace record [<options>] [<command>]",
2935 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002936 NULL
2937 };
2938 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002939 .syscalls = {
2940 . max = -1,
2941 },
2942 .opts = {
2943 .target = {
2944 .uid = UINT_MAX,
2945 .uses_mmap = true,
2946 },
2947 .user_freq = UINT_MAX,
2948 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002949 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002950 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002951 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002952 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002953 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002954 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002955 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002956 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002957 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002958 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002959 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002960 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002961 OPT_CALLBACK('e', "event", &trace, "event",
2962 "event/syscall selector. use 'perf list' to list available events",
2963 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002964 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2965 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002966 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002967 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2968 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002969 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002970 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002971 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2972 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002973 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002974 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002975 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2976 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002977 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002978 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002979 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002980 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002981 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002982 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002983 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2984 "number of mmap data pages",
2985 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002986 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002987 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002988 OPT_CALLBACK(0, "duration", &trace, "float",
2989 "show only events with duration > N.M ms",
2990 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002991 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002992 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002993 OPT_BOOLEAN('T', "time", &trace.full_time,
2994 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002995 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2996 "Show only syscall summary with statistics"),
2997 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2998 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002999 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3000 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003001 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003002 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003003 OPT_CALLBACK(0, "call-graph", &trace.opts,
3004 "record_mode[,record_size]", record_callchain_help,
3005 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003006 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3007 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003008 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3009 "Set the minimum stack depth when parsing the callchain, "
3010 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003011 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3012 "Set the maximum stack depth when parsing the callchain, "
3013 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003014 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003015 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3016 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003017 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3018 "ms to wait before starting measurement after program "
3019 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003020 OPT_END()
3021 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003022 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003023 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003024 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003025 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003026 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003027
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003028 signal(SIGSEGV, sighandler_dump_stack);
3029 signal(SIGFPE, sighandler_dump_stack);
3030
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003031 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003032 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003033
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003034 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003035 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003036 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003037 goto out;
3038 }
3039
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003040 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3041 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003042
Wang Nand7888572016-04-08 15:07:24 +00003043 err = bpf__setup_stdout(trace.evlist);
3044 if (err) {
3045 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3046 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3047 goto out;
3048 }
3049
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003050 err = -1;
3051
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003052 if (trace.trace_pgfaults) {
3053 trace.opts.sample_address = true;
3054 trace.opts.sample_time = true;
3055 }
3056
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003057 if (trace.opts.mmap_pages == UINT_MAX)
3058 mmap_pages_user_set = false;
3059
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003060 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003061 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003062 max_stack_user_set = false;
3063 }
3064
3065#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003066 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003067 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3068#endif
3069
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003070 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003071 if (!mmap_pages_user_set && geteuid() == 0)
3072 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3073
Milian Wolff566a0882016-04-08 13:34:15 +02003074 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003075 }
Milian Wolff566a0882016-04-08 13:34:15 +02003076
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003077 if (trace.evlist->nr_entries > 0)
3078 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3079
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003080 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3081 return trace__record(&trace, argc-1, &argv[1]);
3082
3083 /* summary_only implies summary option, but don't overwrite summary if set */
3084 if (trace.summary_only)
3085 trace.summary = trace.summary_only;
3086
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003087 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3088 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003089 pr_err("Please specify something to trace.\n");
3090 return -1;
3091 }
3092
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003093 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003094 pr_err("The -e option can't be used with --no-syscalls.\n");
3095 goto out;
3096 }
3097
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003098 if (output_name != NULL) {
3099 err = trace__open_output(&trace, output_name);
3100 if (err < 0) {
3101 perror("failed to create output file");
3102 goto out;
3103 }
3104 }
3105
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003106 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3107
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003108 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003109 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003110 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003111 fprintf(trace.output, "%s", bf);
3112 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003113 }
3114
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003115 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003116 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003117 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003118 fprintf(trace.output, "%s", bf);
3119 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003120 }
3121
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003122 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003123 trace.opts.target.system_wide = true;
3124
David Ahern6810fc92013-08-28 22:29:52 -06003125 if (input_name)
3126 err = trace__replay(&trace);
3127 else
3128 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003129
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003130out_close:
3131 if (output_name != NULL)
3132 fclose(trace.output);
3133out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003134 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003135}