blob: 531d43bf57e19e9e21eb5d9a259987586d03dc2c [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 Ahern55d43bc2015-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 Ahern55d43bc2015-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 = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300582 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300583 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300584 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300585 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300586 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300587 { .name = "clone", .errpid = true, .nr_args = 5,
588 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
589 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
590 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
591 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
592 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300593 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300594 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300595 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300596 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300597 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300598 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300599 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300600 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300601 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300602 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300603 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300604 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300605 .parm = &strarrays__fcntl_cmds_arrays,
606 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300607 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300608 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300609 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300610 { .name = "fstat", .alias = "newfstat", },
611 { .name = "fstatat", .alias = "newfstatat", },
612 { .name = "futex",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300613 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300614 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300615 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300616 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300617 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300618 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300619 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300620 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300621 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300623 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300624 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo2d1073d2018-01-09 12:03:47 -0300625 { .name = "gettid", .errpid = true, },
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 Melo1de30382017-10-31 11:32:23 -0300637 { .name = "kcmp", .nr_args = 5,
638 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
639 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
640 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
641 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
642 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300643 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300644 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300645 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300646 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300647 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300648 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300649 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300650 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300651 { .name = "lstat", .alias = "newlstat", },
652 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
654 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300655 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300656 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300657 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300658 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300659 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300660 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300661 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300662 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300663 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200664/* The standard mmap maps to old_mmap on s390x */
665#if defined(__s390x__)
666 .alias = "old_mmap",
667#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300668 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
669 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
670 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300671 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300672 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
673 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300676 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300677 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
678 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
679 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300680 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300681 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300682 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300683 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300684 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300685 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300686 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300688 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300689 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300690 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300691 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
692 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300693 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300694 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
695 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300696 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300697 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
698 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
699 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300700 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300701 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300702 { .name = "pkey_alloc",
703 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
704 { .name = "pkey_free",
705 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
706 { .name = "pkey_mprotect",
707 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
708 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
709 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300710 { .name = "poll", .timeout = true, },
711 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300712 { .name = "prctl", .alias = "arch_prctl",
713 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
714 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
715 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300716 { .name = "pread", .alias = "pread64", },
717 { .name = "preadv", .alias = "pread", },
718 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300719 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300720 { .name = "pwrite", .alias = "pwrite64", },
721 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300722 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300723 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300724 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300726 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300727 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300728 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300730 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300731 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300732 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300733 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300734 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300735 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300736 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300737 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300738 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300739 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300740 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300741 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300742 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
743 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "select", .timeout = true, },
745 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300746 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300747 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300748 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300750 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300751 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300756 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300757 .arg = { [0] = STRARRAY(family, socket_families),
758 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300759 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300760 .arg = { [0] = STRARRAY(family, socket_families),
761 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "stat", .alias = "newstat", },
763 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300764 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
765 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
766 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300767 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300768 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300769 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300770 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300771 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300772 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300773 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300774 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300775 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300776 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300777 { .name = "uname", .alias = "newuname", },
778 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300779 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300780 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300781 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300782 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300783 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300784 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300785 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300786};
787
788static int syscall_fmt__cmp(const void *name, const void *fmtp)
789{
790 const struct syscall_fmt *fmt = fmtp;
791 return strcmp(name, fmt->name);
792}
793
794static struct syscall_fmt *syscall_fmt__find(const char *name)
795{
796 const int nmemb = ARRAY_SIZE(syscall_fmts);
797 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
798}
799
800struct syscall {
801 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300802 int nr_args;
803 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300804 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300805 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300806 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300807 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300808};
809
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300810/*
811 * We need to have this 'calculated' boolean because in some cases we really
812 * don't know what is the duration of a syscall, for instance, when we start
813 * a session and some threads are waiting for a syscall to finish, say 'poll',
814 * in which case all we can do is to print "( ? ) for duration and for the
815 * start timestamp.
816 */
817static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200818{
819 double duration = (double)t / NSEC_PER_MSEC;
820 size_t printed = fprintf(fp, "(");
821
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300822 if (!calculated)
823 printed += fprintf(fp, " ? ");
824 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200825 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
826 else if (duration >= 0.01)
827 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
828 else
829 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300830 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200831}
832
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300833/**
834 * filename.ptr: The filename char pointer that will be vfs_getname'd
835 * filename.entry_str_pos: Where to insert the string translated from
836 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300837 * ret_scnprintf: syscall args may set this to a different syscall return
838 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300839 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300840struct thread_trace {
841 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300842 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300843 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400844 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300845 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300846 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300847 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300848 struct {
849 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300850 short int entry_str_pos;
851 bool pending_open;
852 unsigned int namelen;
853 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300854 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300855 struct {
856 int max;
857 char **table;
858 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600859
860 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300861};
862
863static struct thread_trace *thread_trace__new(void)
864{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300865 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
866
867 if (ttrace)
868 ttrace->paths.max = -1;
869
David Ahernbf2575c2013-10-08 21:26:53 -0600870 ttrace->syscall_stats = intlist__new(NULL);
871
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300872 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300873}
874
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300875static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300877 struct thread_trace *ttrace;
878
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300879 if (thread == NULL)
880 goto fail;
881
Namhyung Kim89dceb22014-10-06 09:46:03 +0900882 if (thread__priv(thread) == NULL)
883 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300884
Namhyung Kim89dceb22014-10-06 09:46:03 +0900885 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300886 goto fail;
887
Namhyung Kim89dceb22014-10-06 09:46:03 +0900888 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300889 ++ttrace->nr_events;
890
891 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300892fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300893 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300894 "WARNING: not enough memory, dropping samples!\n");
895 return NULL;
896}
897
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300898
899void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300900 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300901{
902 struct thread_trace *ttrace = thread__priv(arg->thread);
903
904 ttrace->ret_scnprintf = ret_scnprintf;
905}
906
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400907#define TRACE_PFMAJ (1 << 0)
908#define TRACE_PFMIN (1 << 1)
909
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300910static const size_t trace__entry_str_size = 2048;
911
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300912static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300913{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900914 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300915
916 if (fd > ttrace->paths.max) {
917 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
918
919 if (npath == NULL)
920 return -1;
921
922 if (ttrace->paths.max != -1) {
923 memset(npath + ttrace->paths.max + 1, 0,
924 (fd - ttrace->paths.max) * sizeof(char *));
925 } else {
926 memset(npath, 0, (fd + 1) * sizeof(char *));
927 }
928
929 ttrace->paths.table = npath;
930 ttrace->paths.max = fd;
931 }
932
933 ttrace->paths.table[fd] = strdup(pathname);
934
935 return ttrace->paths.table[fd] != NULL ? 0 : -1;
936}
937
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300938static int thread__read_fd_path(struct thread *thread, int fd)
939{
940 char linkname[PATH_MAX], pathname[PATH_MAX];
941 struct stat st;
942 int ret;
943
944 if (thread->pid_ == thread->tid) {
945 scnprintf(linkname, sizeof(linkname),
946 "/proc/%d/fd/%d", thread->pid_, fd);
947 } else {
948 scnprintf(linkname, sizeof(linkname),
949 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
950 }
951
952 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
953 return -1;
954
955 ret = readlink(linkname, pathname, sizeof(pathname));
956
957 if (ret < 0 || ret > st.st_size)
958 return -1;
959
960 pathname[ret] = '\0';
961 return trace__set_fd_pathname(thread, fd, pathname);
962}
963
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300964static const char *thread__fd_path(struct thread *thread, int fd,
965 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300966{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900967 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300968
969 if (ttrace == NULL)
970 return NULL;
971
972 if (fd < 0)
973 return NULL;
974
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300975 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300976 if (!trace->live)
977 return NULL;
978 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300979 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300980 return NULL;
981 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982
983 return ttrace->paths.table[fd];
984}
985
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -0300986size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300987{
988 int fd = arg->val;
989 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300990 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300991
992 if (path)
993 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
994
995 return printed;
996}
997
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -0300998size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
999{
1000 size_t printed = scnprintf(bf, size, "%d", fd);
1001 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1002
1003 if (thread) {
1004 const char *path = thread__fd_path(thread, fd, trace);
1005
1006 if (path)
1007 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1008
1009 thread__put(thread);
1010 }
1011
1012 return printed;
1013}
1014
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001015static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1016 struct syscall_arg *arg)
1017{
1018 int fd = arg->val;
1019 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001020 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001022 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1023 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001024
1025 return printed;
1026}
1027
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001028static void thread__set_filename_pos(struct thread *thread, const char *bf,
1029 unsigned long ptr)
1030{
1031 struct thread_trace *ttrace = thread__priv(thread);
1032
1033 ttrace->filename.ptr = ptr;
1034 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1035}
1036
1037static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1038 struct syscall_arg *arg)
1039{
1040 unsigned long ptr = arg->val;
1041
1042 if (!arg->trace->vfs_getname)
1043 return scnprintf(bf, size, "%#x", ptr);
1044
1045 thread__set_filename_pos(arg->thread, bf, ptr);
1046 return 0;
1047}
1048
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001049static bool trace__filter_duration(struct trace *trace, double t)
1050{
1051 return t < (trace->duration_filter * NSEC_PER_MSEC);
1052}
1053
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001054static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001055{
1056 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1057
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001058 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001059}
1060
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001061/*
1062 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1063 * using ttrace->entry_time for a thread that receives a sys_exit without
1064 * first having received a sys_enter ("poll" issued before tracing session
1065 * starts, lost sys_enter exit due to ring buffer overflow).
1066 */
1067static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1068{
1069 if (tstamp > 0)
1070 return __trace__fprintf_tstamp(trace, tstamp, fp);
1071
1072 return fprintf(fp, " ? ");
1073}
1074
Namhyung Kimf15eb532012-10-05 14:02:16 +09001075static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001076static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001077
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001078static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001079{
1080 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001081 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001082}
1083
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001085 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086{
1087 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001088 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001089
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001090 if (trace->multiple_threads) {
1091 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001092 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001093 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001094 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001095
1096 return printed;
1097}
1098
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001099static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001100 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101{
1102 int ret = 0;
1103
1104 switch (event->header.type) {
1105 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001106 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001108 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001109 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001111 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001112 break;
1113 }
1114
1115 return ret;
1116}
1117
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001118static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001119 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001120 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121 struct machine *machine)
1122{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001123 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001124 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125}
1126
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001127static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1128{
1129 struct machine *machine = vmachine;
1130
1131 if (machine->kptr_restrict_warned)
1132 return NULL;
1133
1134 if (symbol_conf.kptr_restrict) {
1135 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1136 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1137 "Kernel samples will not be resolved.\n");
1138 machine->kptr_restrict_warned = true;
1139 return NULL;
1140 }
1141
1142 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1143}
1144
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1146{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001147 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148
1149 if (err)
1150 return err;
1151
David Ahern8fb598e2013-09-28 13:13:00 -06001152 trace->host = machine__new_host();
1153 if (trace->host == NULL)
1154 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155
Andrei Vagincbd5c172017-11-07 16:22:46 -08001156 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1157 if (err < 0)
1158 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001159
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001160 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001161 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001162 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001163out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001164 if (err)
1165 symbol__exit();
1166
1167 return err;
1168}
1169
Andrei Vagin33974a42017-11-07 16:22:45 -08001170static void trace__symbols__exit(struct trace *trace)
1171{
1172 machine__exit(trace->host);
1173 trace->host = NULL;
1174
1175 symbol__exit();
1176}
1177
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001178static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1179{
1180 int idx;
1181
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001182 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1183 nr_args = sc->fmt->nr_args;
1184
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001185 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1186 if (sc->arg_fmt == NULL)
1187 return -1;
1188
1189 for (idx = 0; idx < nr_args; ++idx) {
1190 if (sc->fmt)
1191 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1192 }
1193
1194 sc->nr_args = nr_args;
1195 return 0;
1196}
1197
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001198static int syscall__set_arg_fmts(struct syscall *sc)
1199{
1200 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001201 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001202
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001203 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001204 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1205 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001206
1207 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001208 (strcmp(field->name, "filename") == 0 ||
1209 strcmp(field->name, "path") == 0 ||
1210 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001211 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001212 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001213 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001214 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001215 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001216 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001217 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001218 else if ((strcmp(field->type, "int") == 0 ||
1219 strcmp(field->type, "unsigned int") == 0 ||
1220 strcmp(field->type, "long") == 0) &&
1221 (len = strlen(field->name)) >= 2 &&
1222 strcmp(field->name + len - 2, "fd") == 0) {
1223 /*
1224 * /sys/kernel/tracing/events/syscalls/sys_enter*
1225 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1226 * 65 int
1227 * 23 unsigned int
1228 * 7 unsigned long
1229 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001230 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001231 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001232 }
1233
1234 return 0;
1235}
1236
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001237static int trace__read_syscall_info(struct trace *trace, int id)
1238{
1239 char tp_name[128];
1240 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001241 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001242
1243 if (name == NULL)
1244 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001245
1246 if (id > trace->syscalls.max) {
1247 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1248
1249 if (nsyscalls == NULL)
1250 return -1;
1251
1252 if (trace->syscalls.max != -1) {
1253 memset(nsyscalls + trace->syscalls.max + 1, 0,
1254 (id - trace->syscalls.max) * sizeof(*sc));
1255 } else {
1256 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1257 }
1258
1259 trace->syscalls.table = nsyscalls;
1260 trace->syscalls.max = id;
1261 }
1262
1263 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001264 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001265
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001266 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001267
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001268 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001269 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001270
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001271 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001272 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001273 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001274 }
1275
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001276 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1277 return -1;
1278
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001279 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001280 return -1;
1281
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001282 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001283 /*
1284 * We need to check and discard the first variable '__syscall_nr'
1285 * or 'nr' that mean the syscall number. It is needless here.
1286 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1287 */
1288 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001289 sc->args = sc->args->next;
1290 --sc->nr_args;
1291 }
1292
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001293 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1294
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001295 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001296}
1297
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001298static int trace__validate_ev_qualifier(struct trace *trace)
1299{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001300 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001301 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001302 struct str_node *pos;
1303
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001304 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1305 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1306 sizeof(trace->ev_qualifier_ids.entries[0]));
1307
1308 if (trace->ev_qualifier_ids.entries == NULL) {
1309 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1310 trace->output);
1311 err = -EINVAL;
1312 goto out;
1313 }
1314
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001315 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001316 i = 0;
1317
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001318 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001319 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001320 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001321
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001322 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001323 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1324 if (id >= 0)
1325 goto matches;
1326
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001327 if (err == 0) {
1328 fputs("Error:\tInvalid syscall ", trace->output);
1329 err = -EINVAL;
1330 } else {
1331 fputs(", ", trace->output);
1332 }
1333
1334 fputs(sc, trace->output);
1335 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001336matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001337 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001338 if (match_next == -1)
1339 continue;
1340
1341 while (1) {
1342 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1343 if (id < 0)
1344 break;
1345 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1346 void *entries;
1347
1348 nr_allocated += 8;
1349 entries = realloc(trace->ev_qualifier_ids.entries,
1350 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1351 if (entries == NULL) {
1352 err = -ENOMEM;
1353 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1354 goto out_free;
1355 }
1356 trace->ev_qualifier_ids.entries = entries;
1357 }
1358 trace->ev_qualifier_ids.nr++;
1359 trace->ev_qualifier_ids.entries[i++] = id;
1360 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001361 }
1362
1363 if (err < 0) {
1364 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1365 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001366out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001367 zfree(&trace->ev_qualifier_ids.entries);
1368 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001369 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001370out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001371 return err;
1372}
1373
David Ahern55d43bc2015-02-19 15:00:22 -05001374/*
1375 * args is to be interpreted as a series of longs but we need to handle
1376 * 8-byte unaligned accesses. args points to raw_data within the event
1377 * and raw_data is guaranteed to be 8-byte unaligned because it is
1378 * preceded by raw_size which is a u32. So we need to copy args to a temp
1379 * variable to read it. Most notably this avoids extended load instructions
1380 * on unaligned addresses
1381 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001382unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001383{
1384 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001385 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001386
1387 memcpy(&val, p, sizeof(val));
1388 return val;
1389}
1390
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001391static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1392 struct syscall_arg *arg)
1393{
1394 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1395 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1396
1397 return scnprintf(bf, size, "arg%d: ", arg->idx);
1398}
1399
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001400static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1401 struct syscall_arg *arg, unsigned long val)
1402{
1403 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1404 arg->val = val;
1405 if (sc->arg_fmt[arg->idx].parm)
1406 arg->parm = sc->arg_fmt[arg->idx].parm;
1407 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1408 }
1409 return scnprintf(bf, size, "%ld", val);
1410}
1411
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001412static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001413 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001414 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001415{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001416 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001417 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001418 u8 bit = 1;
1419 struct syscall_arg arg = {
1420 .args = args,
1421 .idx = 0,
1422 .mask = 0,
1423 .trace = trace,
1424 .thread = thread,
1425 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001426 struct thread_trace *ttrace = thread__priv(thread);
1427
1428 /*
1429 * Things like fcntl will set this in its 'cmd' formatter to pick the
1430 * right formatter for the return value (an fd? file flags?), which is
1431 * not needed for syscalls that always return a given type, say an fd.
1432 */
1433 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001434
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001435 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001436 struct format_field *field;
1437
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001438 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001439 field = field->next, ++arg.idx, bit <<= 1) {
1440 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001441 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001442
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001443 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bc2015-02-19 15:00:22 -05001444
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001445 /*
1446 * Suppress this argument if its value is zero and
1447 * and we don't have a string associated in an
1448 * strarray for it.
1449 */
David Ahern55d43bc2015-02-19 15:00:22 -05001450 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001451 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001452 (sc->arg_fmt[arg.idx].show_zero ||
1453 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001454 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1455 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001456 continue;
1457
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001458 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001459 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001460 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001461 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001462 } else if (IS_ERR(sc->tp_format)) {
1463 /*
1464 * If we managed to read the tracepoint /format file, then we
1465 * may end up not having any args, like with gettid(), so only
1466 * print the raw args when we didn't manage to read it.
1467 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001468 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001469 if (arg.mask & bit)
1470 goto next_arg;
1471 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001472 if (printed)
1473 printed += scnprintf(bf + printed, size - printed, ", ");
1474 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001475 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1476next_arg:
1477 ++arg.idx;
1478 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001479 }
1480 }
1481
1482 return printed;
1483}
1484
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001485typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001486 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001487 struct perf_sample *sample);
1488
1489static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001490 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001491{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001492
1493 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001494
1495 /*
1496 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1497 * before that, leaving at a higher verbosity level till that is
1498 * explained. Reproduced with plain ftrace with:
1499 *
1500 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1501 * grep "NR -1 " /t/trace_pipe
1502 *
1503 * After generating some load on the machine.
1504 */
1505 if (verbose > 1) {
1506 static u64 n;
1507 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1508 id, perf_evsel__name(evsel), ++n);
1509 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001510 return NULL;
1511 }
1512
1513 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1514 trace__read_syscall_info(trace, id))
1515 goto out_cant_read;
1516
1517 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1518 goto out_cant_read;
1519
1520 return &trace->syscalls.table[id];
1521
1522out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001523 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001524 fprintf(trace->output, "Problems reading syscall %d", id);
1525 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1526 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1527 fputs(" information\n", trace->output);
1528 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001529 return NULL;
1530}
1531
David Ahernbf2575c2013-10-08 21:26:53 -06001532static void thread__update_stats(struct thread_trace *ttrace,
1533 int id, struct perf_sample *sample)
1534{
1535 struct int_node *inode;
1536 struct stats *stats;
1537 u64 duration = 0;
1538
1539 inode = intlist__findnew(ttrace->syscall_stats, id);
1540 if (inode == NULL)
1541 return;
1542
1543 stats = inode->priv;
1544 if (stats == NULL) {
1545 stats = malloc(sizeof(struct stats));
1546 if (stats == NULL)
1547 return;
1548 init_stats(stats);
1549 inode->priv = stats;
1550 }
1551
1552 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1553 duration = sample->time - ttrace->entry_time;
1554
1555 update_stats(stats, duration);
1556}
1557
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001558static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1559{
1560 struct thread_trace *ttrace;
1561 u64 duration;
1562 size_t printed;
1563
1564 if (trace->current == NULL)
1565 return 0;
1566
1567 ttrace = thread__priv(trace->current);
1568
1569 if (!ttrace->entry_pending)
1570 return 0;
1571
1572 duration = sample->time - ttrace->entry_time;
1573
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001574 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001575 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1576 ttrace->entry_pending = false;
1577
1578 return printed;
1579}
1580
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001581static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001582 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001583 struct perf_sample *sample)
1584{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001585 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001586 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001587 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001588 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001589 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001590 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001591 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001592
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001593 if (sc == NULL)
1594 return -1;
1595
David Ahern8fb598e2013-09-28 13:13:00 -06001596 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001597 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001598 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001599 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001600
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001601 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001602
1603 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001604 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001605 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001606 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001607 }
1608
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001609 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001610 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001611
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001612 ttrace->entry_time = sample->time;
1613 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001614 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001615
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001616 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001617 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001618
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001619 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001620 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001621 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001622 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001623 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001624 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001625 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001626 /* See trace__vfs_getname & trace__sys_exit */
1627 ttrace->filename.pending_open = false;
1628 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001629
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001630 if (trace->current != thread) {
1631 thread__put(trace->current);
1632 trace->current = thread__get(thread);
1633 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001634 err = 0;
1635out_put:
1636 thread__put(thread);
1637 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001638}
1639
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001640static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1641 struct perf_sample *sample,
1642 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001643{
1644 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001645
1646 if (machine__resolve(trace->host, &al, sample) < 0 ||
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03001647 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, evsel->attr.sample_max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001648 return -1;
1649
1650 return 0;
1651}
1652
1653static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1654{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001655 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001656 const unsigned int print_opts = EVSEL__PRINT_SYM |
1657 EVSEL__PRINT_DSO |
1658 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001659
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001660 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001661}
1662
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001663static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001664 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001665 struct perf_sample *sample)
1666{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001667 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001668 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001669 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001670 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001671 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001672 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001673 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001674
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001675 if (sc == NULL)
1676 return -1;
1677
David Ahern8fb598e2013-09-28 13:13:00 -06001678 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001679 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001680 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001681 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001682
David Ahernbf2575c2013-10-08 21:26:53 -06001683 if (trace->summary)
1684 thread__update_stats(ttrace, id, sample);
1685
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001686 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001687
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001688 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001689 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1690 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001691 ++trace->stats.vfs_getname;
1692 }
1693
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001694 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001695 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001696 if (trace__filter_duration(trace, duration))
1697 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001698 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001699 } else if (trace->duration_filter)
1700 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001701
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001702 if (sample->callchain) {
1703 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1704 if (callchain_ret == 0) {
1705 if (callchain_cursor.nr < trace->min_stack)
1706 goto out;
1707 callchain_ret = 1;
1708 }
1709 }
1710
David Ahernfd2eaba2013-11-12 09:31:15 -07001711 if (trace->summary_only)
1712 goto out;
1713
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001714 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001715
1716 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001717 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001718 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719 fprintf(trace->output, " ... [");
1720 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1721 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001722 }
1723
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001724 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001725 if (ret < 0)
1726 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001727signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001728 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001729 } else if (ret < 0) {
1730errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001731 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001732 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001733 *e = audit_errno_to_name(-ret);
1734
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001735 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001736 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001737 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001738 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001739 else if (ttrace->ret_scnprintf) {
1740 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001741 struct syscall_arg arg = {
1742 .val = ret,
1743 .thread = thread,
1744 .trace = trace,
1745 };
1746 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001747 ttrace->ret_scnprintf = NULL;
1748 fprintf(trace->output, ") = %s", bf);
1749 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001750 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001751 else if (sc->fmt->errpid) {
1752 struct thread *child = machine__find_thread(trace->host, ret, ret);
1753
1754 if (child != NULL) {
1755 fprintf(trace->output, ") = %ld", ret);
1756 if (child->comm_set)
1757 fprintf(trace->output, " (%s)", thread__comm_str(child));
1758 thread__put(child);
1759 }
1760 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001761 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001762
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001763 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001764
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001765 if (callchain_ret > 0)
1766 trace__fprintf_callchain(trace, sample);
1767 else if (callchain_ret < 0)
1768 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001769out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001770 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001771 err = 0;
1772out_put:
1773 thread__put(thread);
1774 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001775}
1776
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001777static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001778 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001779 struct perf_sample *sample)
1780{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001781 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1782 struct thread_trace *ttrace;
1783 size_t filename_len, entry_str_len, to_move;
1784 ssize_t remaining_space;
1785 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001786 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001787
1788 if (!thread)
1789 goto out;
1790
1791 ttrace = thread__priv(thread);
1792 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001793 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001794
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001795 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001796 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001797 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001798
1799 if (ttrace->filename.namelen < filename_len) {
1800 char *f = realloc(ttrace->filename.name, filename_len + 1);
1801
1802 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001803 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001804
1805 ttrace->filename.namelen = filename_len;
1806 ttrace->filename.name = f;
1807 }
1808
1809 strcpy(ttrace->filename.name, filename);
1810 ttrace->filename.pending_open = true;
1811
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001812 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001813 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001814
1815 entry_str_len = strlen(ttrace->entry_str);
1816 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1817 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001818 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001819
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001820 if (filename_len > (size_t)remaining_space) {
1821 filename += filename_len - remaining_space;
1822 filename_len = remaining_space;
1823 }
1824
1825 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1826 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1827 memmove(pos + filename_len, pos, to_move);
1828 memcpy(pos, filename, filename_len);
1829
1830 ttrace->filename.ptr = 0;
1831 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001832out_put:
1833 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001834out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001835 return 0;
1836}
1837
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001838static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001839 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001840 struct perf_sample *sample)
1841{
1842 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1843 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001844 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001845 sample->pid,
1846 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001847 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001848
1849 if (ttrace == NULL)
1850 goto out_dump;
1851
1852 ttrace->runtime_ms += runtime_ms;
1853 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001854out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001855 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001856 return 0;
1857
1858out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001859 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001860 evsel->name,
1861 perf_evsel__strval(evsel, sample, "comm"),
1862 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1863 runtime,
1864 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001865 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001866}
1867
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001868static int bpf_output__printer(enum binary_printer_ops op,
1869 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001870{
Wang Nan1d6c9402016-02-26 09:31:55 +00001871 unsigned char ch = (unsigned char)val;
1872
1873 switch (op) {
1874 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001875 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001876 case BINARY_PRINT_DATA_BEGIN:
1877 case BINARY_PRINT_LINE_BEGIN:
1878 case BINARY_PRINT_ADDR:
1879 case BINARY_PRINT_NUM_DATA:
1880 case BINARY_PRINT_NUM_PAD:
1881 case BINARY_PRINT_SEP:
1882 case BINARY_PRINT_CHAR_PAD:
1883 case BINARY_PRINT_LINE_END:
1884 case BINARY_PRINT_DATA_END:
1885 default:
1886 break;
1887 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001888
1889 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001890}
1891
1892static void bpf_output__fprintf(struct trace *trace,
1893 struct perf_sample *sample)
1894{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001895 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1896 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001897}
1898
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001899static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1900 union perf_event *event __maybe_unused,
1901 struct perf_sample *sample)
1902{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001903 int callchain_ret = 0;
1904
1905 if (sample->callchain) {
1906 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1907 if (callchain_ret == 0) {
1908 if (callchain_cursor.nr < trace->min_stack)
1909 goto out;
1910 callchain_ret = 1;
1911 }
1912 }
1913
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001914 trace__printf_interrupted_entry(trace, sample);
1915 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001916
1917 if (trace->trace_syscalls)
1918 fprintf(trace->output, "( ): ");
1919
1920 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001921
Wang Nan1d6c9402016-02-26 09:31:55 +00001922 if (perf_evsel__is_bpf_output(evsel)) {
1923 bpf_output__fprintf(trace, sample);
1924 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001925 event_format__fprintf(evsel->tp_format, sample->cpu,
1926 sample->raw_data, sample->raw_size,
1927 trace->output);
1928 }
1929
1930 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001931
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001932 if (callchain_ret > 0)
1933 trace__fprintf_callchain(trace, sample);
1934 else if (callchain_ret < 0)
1935 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1936out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001937 return 0;
1938}
1939
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001940static void print_location(FILE *f, struct perf_sample *sample,
1941 struct addr_location *al,
1942 bool print_dso, bool print_sym)
1943{
1944
Namhyung Kimbb963e12017-02-17 17:17:38 +09001945 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001946 fprintf(f, "%s@", al->map->dso->long_name);
1947
Namhyung Kimbb963e12017-02-17 17:17:38 +09001948 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001949 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001950 al->addr - al->sym->start);
1951 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001952 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001953 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001954 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001955}
1956
1957static int trace__pgfault(struct trace *trace,
1958 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001959 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001960 struct perf_sample *sample)
1961{
1962 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001963 struct addr_location al;
1964 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001965 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001966 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001967 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001968
1969 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001970
1971 if (sample->callchain) {
1972 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1973 if (callchain_ret == 0) {
1974 if (callchain_cursor.nr < trace->min_stack)
1975 goto out_put;
1976 callchain_ret = 1;
1977 }
1978 }
1979
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001980 ttrace = thread__trace(thread, trace->output);
1981 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001982 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001983
1984 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1985 ttrace->pfmaj++;
1986 else
1987 ttrace->pfmin++;
1988
1989 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001990 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001991
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001992 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001993 sample->ip, &al);
1994
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001995 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001996
1997 fprintf(trace->output, "%sfault [",
1998 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1999 "maj" : "min");
2000
2001 print_location(trace->output, sample, &al, false, true);
2002
2003 fprintf(trace->output, "] => ");
2004
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002005 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002006 sample->addr, &al);
2007
2008 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002009 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002010 MAP__FUNCTION, sample->addr, &al);
2011
2012 if (al.map)
2013 map_type = 'x';
2014 else
2015 map_type = '?';
2016 }
2017
2018 print_location(trace->output, sample, &al, true, false);
2019
2020 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002021
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002022 if (callchain_ret > 0)
2023 trace__fprintf_callchain(trace, sample);
2024 else if (callchain_ret < 0)
2025 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002026out:
2027 err = 0;
2028out_put:
2029 thread__put(thread);
2030 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002031}
2032
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002033static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002034 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002035 struct perf_sample *sample)
2036{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002037 /*
2038 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2039 * and don't use sample->time unconditionally, we may end up having
2040 * some other event in the future without PERF_SAMPLE_TIME for good
2041 * reason, i.e. we may not be interested in its timestamps, just in
2042 * it taking place, picking some piece of information when it
2043 * appears in our event stream (vfs_getname comes to mind).
2044 */
2045 if (trace->base_time == 0 && !trace->full_time &&
2046 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002047 trace->base_time = sample->time;
2048}
2049
David Ahern6810fc92013-08-28 22:29:52 -06002050static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002051 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002052 struct perf_sample *sample,
2053 struct perf_evsel *evsel,
2054 struct machine *machine __maybe_unused)
2055{
2056 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002057 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002058 int err = 0;
2059
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002060 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002061
David Ahernaa07df62016-11-25 09:29:52 -07002062 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2063 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002064 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002065
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002066 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002067
David Ahern31605652013-12-04 19:41:41 -07002068 if (handler) {
2069 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002070 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002071 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002072out:
2073 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002074 return err;
2075}
2076
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002077static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002078{
2079 unsigned int rec_argc, i, j;
2080 const char **rec_argv;
2081 const char * const record_args[] = {
2082 "record",
2083 "-R",
2084 "-m", "1024",
2085 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002086 };
2087
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002088 const char * const sc_args[] = { "-e", };
2089 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2090 const char * const majpf_args[] = { "-e", "major-faults" };
2091 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2092 const char * const minpf_args[] = { "-e", "minor-faults" };
2093 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2094
David Ahern9aca7f12013-12-04 19:41:39 -07002095 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002096 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2097 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002098 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2099
2100 if (rec_argv == NULL)
2101 return -ENOMEM;
2102
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002103 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002104 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002105 rec_argv[j++] = record_args[i];
2106
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002107 if (trace->trace_syscalls) {
2108 for (i = 0; i < sc_args_nr; i++)
2109 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002110
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002111 /* event string may be different for older kernels - e.g., RHEL6 */
2112 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2113 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2114 else if (is_valid_tracepoint("syscalls:sys_enter"))
2115 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2116 else {
2117 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002118 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002119 return -1;
2120 }
David Ahern9aca7f12013-12-04 19:41:39 -07002121 }
David Ahern9aca7f12013-12-04 19:41:39 -07002122
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002123 if (trace->trace_pgfaults & TRACE_PFMAJ)
2124 for (i = 0; i < majpf_args_nr; i++)
2125 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002126
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002127 if (trace->trace_pgfaults & TRACE_PFMIN)
2128 for (i = 0; i < minpf_args_nr; i++)
2129 rec_argv[j++] = minpf_args[i];
2130
2131 for (i = 0; i < (unsigned int)argc; i++)
2132 rec_argv[j++] = argv[i];
2133
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002134 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002135}
2136
David Ahernbf2575c2013-10-08 21:26:53 -06002137static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2138
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002139static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002140{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002141 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002142
2143 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002144 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002145
2146 if (perf_evsel__field(evsel, "pathname") == NULL) {
2147 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002148 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002149 }
2150
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002151 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002152 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002153 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002154}
2155
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002156static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002157{
2158 struct perf_evsel *evsel;
2159 struct perf_event_attr attr = {
2160 .type = PERF_TYPE_SOFTWARE,
2161 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002162 };
2163
2164 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002165 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002166
2167 event_attr_init(&attr);
2168
2169 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002170 if (evsel)
2171 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002172
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002173 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002174}
2175
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002176static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2177{
2178 const u32 type = event->header.type;
2179 struct perf_evsel *evsel;
2180
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002181 if (type != PERF_RECORD_SAMPLE) {
2182 trace__process_event(trace, trace->host, event, sample);
2183 return;
2184 }
2185
2186 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2187 if (evsel == NULL) {
2188 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2189 return;
2190 }
2191
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002192 trace__set_base_time(trace, evsel, sample);
2193
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002194 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2195 sample->raw_data == NULL) {
2196 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2197 perf_evsel__name(evsel), sample->tid,
2198 sample->cpu, sample->raw_size);
2199 } else {
2200 tracepoint_handler handler = evsel->handler;
2201 handler(trace, evsel, event, sample);
2202 }
2203}
2204
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002205static int trace__add_syscall_newtp(struct trace *trace)
2206{
2207 int ret = -1;
2208 struct perf_evlist *evlist = trace->evlist;
2209 struct perf_evsel *sys_enter, *sys_exit;
2210
2211 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2212 if (sys_enter == NULL)
2213 goto out;
2214
2215 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2216 goto out_delete_sys_enter;
2217
2218 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2219 if (sys_exit == NULL)
2220 goto out_delete_sys_enter;
2221
2222 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2223 goto out_delete_sys_exit;
2224
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002225 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2226 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2227
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002228 perf_evlist__add(evlist, sys_enter);
2229 perf_evlist__add(evlist, sys_exit);
2230
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002231 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002232 /*
2233 * We're interested only in the user space callchain
2234 * leading to the syscall, allow overriding that for
2235 * debugging reasons using --kernel_syscall_callchains
2236 */
2237 sys_exit->attr.exclude_callchain_kernel = 1;
2238 }
2239
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002240 trace->syscalls.events.sys_enter = sys_enter;
2241 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002242
2243 ret = 0;
2244out:
2245 return ret;
2246
2247out_delete_sys_exit:
2248 perf_evsel__delete_priv(sys_exit);
2249out_delete_sys_enter:
2250 perf_evsel__delete_priv(sys_enter);
2251 goto out;
2252}
2253
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002254static int trace__set_ev_qualifier_filter(struct trace *trace)
2255{
2256 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002257 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002258 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2259 trace->ev_qualifier_ids.nr,
2260 trace->ev_qualifier_ids.entries);
2261
2262 if (filter == NULL)
2263 goto out_enomem;
2264
Mathieu Poirier3541c032016-09-16 08:44:04 -06002265 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2266 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002267 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002268 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002269 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002270
2271 free(filter);
2272out:
2273 return err;
2274out_enomem:
2275 errno = ENOMEM;
2276 goto out;
2277}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002278
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002279static int trace__set_filter_loop_pids(struct trace *trace)
2280{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002281 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002282 pid_t pids[32] = {
2283 getpid(),
2284 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002285 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2286
2287 while (thread && nr < ARRAY_SIZE(pids)) {
2288 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2289
2290 if (parent == NULL)
2291 break;
2292
2293 if (!strcmp(thread__comm_str(parent), "sshd")) {
2294 pids[nr++] = parent->tid;
2295 break;
2296 }
2297 thread = parent;
2298 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002299
2300 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2301}
2302
Namhyung Kimf15eb532012-10-05 14:02:16 +09002303static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002304{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002305 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002306 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002307 int err = -1, i;
2308 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002309 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002310 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002311
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002312 trace->live = true;
2313
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002314 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002315 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002316
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002317 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002318 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002319
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002320 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2321 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2322 if (pgfault_maj == NULL)
2323 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002324 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002325 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002326 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002327
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002328 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2329 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2330 if (pgfault_min == NULL)
2331 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002332 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002333 perf_evlist__add(evlist, pgfault_min);
2334 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002335
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002336 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002337 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2338 trace__sched_stat_runtime))
2339 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002340
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002341 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2342 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002343 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002344 goto out_delete_evlist;
2345 }
2346
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002347 err = trace__symbols_init(trace, evlist);
2348 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002349 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002350 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002351 }
2352
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002353 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002354
Namhyung Kimf15eb532012-10-05 14:02:16 +09002355 signal(SIGCHLD, sig_handler);
2356 signal(SIGINT, sig_handler);
2357
2358 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002359 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002360 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002361 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002362 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002363 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002364 }
2365 }
2366
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002367 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002368 if (err < 0)
2369 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002370
Wang Nanba504232016-02-26 09:31:54 +00002371 err = bpf__apply_obj_config();
2372 if (err) {
2373 char errbuf[BUFSIZ];
2374
2375 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2376 pr_err("ERROR: Apply config to BPF failed: %s\n",
2377 errbuf);
2378 goto out_error_open;
2379 }
2380
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002381 /*
2382 * Better not use !target__has_task() here because we need to cover the
2383 * case where no threads were specified in the command line, but a
2384 * workload was, and in that case we will fill in the thread_map when
2385 * we fork the workload in perf_evlist__prepare_workload.
2386 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002387 if (trace->filter_pids.nr > 0)
2388 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002389 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002390 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002391
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002392 if (err < 0)
2393 goto out_error_mem;
2394
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002395 if (trace->ev_qualifier_ids.nr > 0) {
2396 err = trace__set_ev_qualifier_filter(trace);
2397 if (err < 0)
2398 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002399
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002400 pr_debug("event qualifier tracepoint filter: %s\n",
2401 trace->syscalls.events.sys_exit->filter);
2402 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002403
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002404 err = perf_evlist__apply_filters(evlist, &evsel);
2405 if (err < 0)
2406 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002407
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002408 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002409 if (err < 0)
2410 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002411
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002412 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002413 perf_evlist__enable(evlist);
2414
Namhyung Kimf15eb532012-10-05 14:02:16 +09002415 if (forks)
2416 perf_evlist__start_workload(evlist);
2417
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002418 if (trace->opts.initial_delay) {
2419 usleep(trace->opts.initial_delay * 1000);
2420 perf_evlist__enable(evlist);
2421 }
2422
Jiri Olsae13798c2015-06-23 00:36:02 +02002423 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002424 evlist->threads->nr > 1 ||
2425 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002426
2427 /*
2428 * Now that we already used evsel->attr to ask the kernel to setup the
2429 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2430 * trace__resolve_callchain(), allowing per-event max-stack settings
2431 * to override an explicitely set --max-stack global setting.
2432 */
2433 evlist__for_each_entry(evlist, evsel) {
2434 if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) &&
2435 evsel->attr.sample_max_stack == 0)
2436 evsel->attr.sample_max_stack = trace->max_stack;
2437 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002438again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002439 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002440
2441 for (i = 0; i < evlist->nr_mmaps; i++) {
2442 union perf_event *event;
2443
2444 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002445 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002446
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002447 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002448
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002449 err = perf_evlist__parse_sample(evlist, event, &sample);
2450 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002451 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002452 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002453 }
2454
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002455 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002456next_event:
2457 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002458
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002459 if (interrupted)
2460 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002461
2462 if (done && !draining) {
2463 perf_evlist__disable(evlist);
2464 draining = true;
2465 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002466 }
2467 }
2468
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002469 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002470 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002471
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002472 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2473 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2474 draining = true;
2475
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002476 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002477 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002478 } else {
2479 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002480 }
2481
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002482out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002483 thread__zput(trace->current);
2484
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002485 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002486
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002487 if (!err) {
2488 if (trace->summary)
2489 trace__fprintf_thread_summary(trace, trace->output);
2490
2491 if (trace->show_tool_stats) {
2492 fprintf(trace->output, "Stats:\n "
2493 " vfs_getname : %" PRIu64 "\n"
2494 " proc_getname: %" PRIu64 "\n",
2495 trace->stats.vfs_getname,
2496 trace->stats.proc_getname);
2497 }
2498 }
David Ahernbf2575c2013-10-08 21:26:53 -06002499
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002500out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002501 trace__symbols__exit(trace);
2502
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002503 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002504 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002505 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002506 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002507{
2508 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002509
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002510out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002511 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002512 goto out_error;
2513
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002514out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002515 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002516 goto out_error;
2517
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002518out_error_mmap:
2519 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2520 goto out_error;
2521
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002522out_error_open:
2523 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2524
2525out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002526 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302527 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002528
2529out_error_apply_filters:
2530 fprintf(trace->output,
2531 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2532 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002533 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002534 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002535}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002536out_error_mem:
2537 fprintf(trace->output, "Not enough memory to run!\n");
2538 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002539
2540out_errno:
2541 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2542 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002543}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002544
David Ahern6810fc92013-08-28 22:29:52 -06002545static int trace__replay(struct trace *trace)
2546{
2547 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002548 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002549 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002550 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002551 .file = {
2552 .path = input_name,
2553 },
2554 .mode = PERF_DATA_MODE_READ,
2555 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002556 };
David Ahern6810fc92013-08-28 22:29:52 -06002557 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002558 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002559 int err = -1;
2560
2561 trace->tool.sample = trace__process_sample;
2562 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002563 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002564 trace->tool.comm = perf_event__process_comm;
2565 trace->tool.exit = perf_event__process_exit;
2566 trace->tool.fork = perf_event__process_fork;
2567 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302568 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002569 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302570 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002571
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002572 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002573 trace->tool.ordering_requires_timestamps = true;
2574
2575 /* add tid to output */
2576 trace->multiple_threads = true;
2577
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002578 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002579 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002580 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002581
David Ahernaa07df62016-11-25 09:29:52 -07002582 if (trace->opts.target.pid)
2583 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2584
2585 if (trace->opts.target.tid)
2586 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2587
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002588 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002589 goto out;
2590
David Ahern8fb598e2013-09-28 13:13:00 -06002591 trace->host = &session->machines.host;
2592
David Ahern6810fc92013-08-28 22:29:52 -06002593 err = perf_session__set_tracepoints_handlers(session, handlers);
2594 if (err)
2595 goto out;
2596
Namhyung Kim003824e2013-11-12 15:25:00 +09002597 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2598 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002599 /* older kernels have syscalls tp versus raw_syscalls */
2600 if (evsel == NULL)
2601 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2602 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002603
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002604 if (evsel &&
2605 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2606 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002607 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2608 goto out;
2609 }
2610
2611 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2612 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002613 if (evsel == NULL)
2614 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2615 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002616 if (evsel &&
2617 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2618 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002619 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002620 goto out;
2621 }
2622
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002623 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002624 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2625 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2626 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2627 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2628 evsel->handler = trace__pgfault;
2629 }
2630
David Ahern6810fc92013-08-28 22:29:52 -06002631 setup_pager();
2632
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002633 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002634 if (err)
2635 pr_err("Failed to process events, error %d", err);
2636
David Ahernbf2575c2013-10-08 21:26:53 -06002637 else if (trace->summary)
2638 trace__fprintf_thread_summary(trace, trace->output);
2639
David Ahern6810fc92013-08-28 22:29:52 -06002640out:
2641 perf_session__delete(session);
2642
2643 return err;
2644}
2645
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002646static size_t trace__fprintf_threads_header(FILE *fp)
2647{
2648 size_t printed;
2649
Pekka Enberg99ff7152013-11-12 16:42:14 +02002650 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002651
2652 return printed;
2653}
2654
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002655DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2656 struct stats *stats;
2657 double msecs;
2658 int syscall;
2659)
2660{
2661 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2662 struct stats *stats = source->priv;
2663
2664 entry->syscall = source->i;
2665 entry->stats = stats;
2666 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2667}
2668
David Ahernbf2575c2013-10-08 21:26:53 -06002669static size_t thread__dump_stats(struct thread_trace *ttrace,
2670 struct trace *trace, FILE *fp)
2671{
David Ahernbf2575c2013-10-08 21:26:53 -06002672 size_t printed = 0;
2673 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002674 struct rb_node *nd;
2675 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002676
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002677 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002678 return 0;
2679
2680 printed += fprintf(fp, "\n");
2681
Milian Wolff834fd462015-08-06 11:24:29 +02002682 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2683 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2684 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002685
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002686 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002687 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002688 if (stats) {
2689 double min = (double)(stats->min) / NSEC_PER_MSEC;
2690 double max = (double)(stats->max) / NSEC_PER_MSEC;
2691 double avg = avg_stats(stats);
2692 double pct;
2693 u64 n = (u64) stats->n;
2694
2695 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2696 avg /= NSEC_PER_MSEC;
2697
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002698 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002699 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002700 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002701 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002702 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002703 }
David Ahernbf2575c2013-10-08 21:26:53 -06002704 }
2705
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002706 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002707 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002708
2709 return printed;
2710}
2711
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002712static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002713{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002714 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002715 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002716 double ratio;
2717
2718 if (ttrace == NULL)
2719 return 0;
2720
2721 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2722
Pekka Enberg15e65c62013-11-14 18:43:30 +02002723 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002724 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002725 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002726 if (ttrace->pfmaj)
2727 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2728 if (ttrace->pfmin)
2729 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002730 if (trace->sched)
2731 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2732 else if (fputc('\n', fp) != EOF)
2733 ++printed;
2734
David Ahernbf2575c2013-10-08 21:26:53 -06002735 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002736
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002737 return printed;
2738}
David Ahern896cbb52013-09-28 13:12:59 -06002739
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002740static unsigned long thread__nr_events(struct thread_trace *ttrace)
2741{
2742 return ttrace ? ttrace->nr_events : 0;
2743}
2744
2745DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2746 struct thread *thread;
2747)
2748{
2749 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002750}
2751
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002752static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2753{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002754 size_t printed = trace__fprintf_threads_header(fp);
2755 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002756 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002757
Kan Liang91e467b2017-09-10 19:23:14 -07002758 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2759 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2760
2761 if (threads == NULL) {
2762 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2763 return 0;
2764 }
2765
2766 resort_rb__for_each_entry(nd, threads)
2767 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2768
2769 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002770 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002771 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002772}
2773
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002774static int trace__set_duration(const struct option *opt, const char *str,
2775 int unset __maybe_unused)
2776{
2777 struct trace *trace = opt->value;
2778
2779 trace->duration_filter = atof(str);
2780 return 0;
2781}
2782
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002783static int trace__set_filter_pids(const struct option *opt, const char *str,
2784 int unset __maybe_unused)
2785{
2786 int ret = -1;
2787 size_t i;
2788 struct trace *trace = opt->value;
2789 /*
2790 * FIXME: introduce a intarray class, plain parse csv and create a
2791 * { int nr, int entries[] } struct...
2792 */
2793 struct intlist *list = intlist__new(str);
2794
2795 if (list == NULL)
2796 return -1;
2797
2798 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2799 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2800
2801 if (trace->filter_pids.entries == NULL)
2802 goto out;
2803
2804 trace->filter_pids.entries[0] = getpid();
2805
2806 for (i = 1; i < trace->filter_pids.nr; ++i)
2807 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2808
2809 intlist__delete(list);
2810 ret = 0;
2811out:
2812 return ret;
2813}
2814
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002815static int trace__open_output(struct trace *trace, const char *filename)
2816{
2817 struct stat st;
2818
2819 if (!stat(filename, &st) && st.st_size) {
2820 char oldname[PATH_MAX];
2821
2822 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2823 unlink(oldname);
2824 rename(filename, oldname);
2825 }
2826
2827 trace->output = fopen(filename, "w");
2828
2829 return trace->output == NULL ? -errno : 0;
2830}
2831
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002832static int parse_pagefaults(const struct option *opt, const char *str,
2833 int unset __maybe_unused)
2834{
2835 int *trace_pgfaults = opt->value;
2836
2837 if (strcmp(str, "all") == 0)
2838 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2839 else if (strcmp(str, "maj") == 0)
2840 *trace_pgfaults |= TRACE_PFMAJ;
2841 else if (strcmp(str, "min") == 0)
2842 *trace_pgfaults |= TRACE_PFMIN;
2843 else
2844 return -1;
2845
2846 return 0;
2847}
2848
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002849static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2850{
2851 struct perf_evsel *evsel;
2852
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002853 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002854 evsel->handler = handler;
2855}
2856
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002857/*
2858 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2859 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2860 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2861 *
2862 * It'd be better to introduce a parse_options() variant that would return a
2863 * list with the terms it didn't match to an event...
2864 */
2865static int trace__parse_events_option(const struct option *opt, const char *str,
2866 int unset __maybe_unused)
2867{
2868 struct trace *trace = (struct trace *)opt->value;
2869 const char *s = str;
2870 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002871 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002872 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2873 char group_name[PATH_MAX];
2874
2875 if (strace_groups_dir == NULL)
2876 return -1;
2877
2878 if (*s == '!') {
2879 ++s;
2880 trace->not_ev_qualifier = true;
2881 }
2882
2883 while (1) {
2884 if ((sep = strchr(s, ',')) != NULL)
2885 *sep = '\0';
2886
2887 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002888 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
2889 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002890 list = 1;
2891 } else {
2892 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2893 if (access(group_name, R_OK) == 0)
2894 list = 1;
2895 }
2896
2897 if (lists[list]) {
2898 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2899 } else {
2900 lists[list] = malloc(len);
2901 if (lists[list] == NULL)
2902 goto out;
2903 strcpy(lists[list], s);
2904 }
2905
2906 if (!sep)
2907 break;
2908
2909 *sep = ',';
2910 s = sep + 1;
2911 }
2912
2913 if (lists[1] != NULL) {
2914 struct strlist_config slist_config = {
2915 .dirname = strace_groups_dir,
2916 };
2917
2918 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2919 if (trace->ev_qualifier == NULL) {
2920 fputs("Not enough memory to parse event qualifier", trace->output);
2921 goto out;
2922 }
2923
2924 if (trace__validate_ev_qualifier(trace))
2925 goto out;
2926 }
2927
2928 err = 0;
2929
2930 if (lists[0]) {
2931 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2932 "event selector. use 'perf list' to list available events",
2933 parse_events_option);
2934 err = parse_events_option(&o, lists[0], 0);
2935 }
2936out:
2937 if (sep)
2938 *sep = ',';
2939
2940 return err;
2941}
2942
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002943int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002944{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002945 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002946 "perf trace [<options>] [<command>]",
2947 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002948 "perf trace record [<options>] [<command>]",
2949 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002950 NULL
2951 };
2952 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002953 .syscalls = {
2954 . max = -1,
2955 },
2956 .opts = {
2957 .target = {
2958 .uid = UINT_MAX,
2959 .uses_mmap = true,
2960 },
2961 .user_freq = UINT_MAX,
2962 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002963 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002964 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002965 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002966 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002967 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002968 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002969 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002970 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002971 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002972 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002973 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002974 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002975 OPT_CALLBACK('e', "event", &trace, "event",
2976 "event/syscall selector. use 'perf list' to list available events",
2977 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002978 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2979 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002980 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002981 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2982 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002983 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002984 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002985 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2986 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002987 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002988 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002989 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2990 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002991 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002992 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002993 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002994 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002995 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002996 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002997 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2998 "number of mmap data pages",
2999 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003000 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003001 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003002 OPT_CALLBACK(0, "duration", &trace, "float",
3003 "show only events with duration > N.M ms",
3004 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003005 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003006 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003007 OPT_BOOLEAN('T', "time", &trace.full_time,
3008 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003009 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3010 "Show only syscall summary with statistics"),
3011 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3012 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003013 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3014 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003015 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003016 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003017 OPT_CALLBACK(0, "call-graph", &trace.opts,
3018 "record_mode[,record_size]", record_callchain_help,
3019 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003020 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3021 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003022 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3023 "Set the minimum stack depth when parsing the callchain, "
3024 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003025 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3026 "Set the maximum stack depth when parsing the callchain, "
3027 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003028 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003029 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3030 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003031 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3032 "ms to wait before starting measurement after program "
3033 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003034 OPT_END()
3035 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003036 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003037 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003038 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003039 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003040 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003041
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003042 signal(SIGSEGV, sighandler_dump_stack);
3043 signal(SIGFPE, sighandler_dump_stack);
3044
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003045 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003046 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003047
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003048 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003049 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003050 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003051 goto out;
3052 }
3053
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003054 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3055 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003056
Wang Nand7888572016-04-08 15:07:24 +00003057 err = bpf__setup_stdout(trace.evlist);
3058 if (err) {
3059 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3060 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3061 goto out;
3062 }
3063
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003064 err = -1;
3065
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003066 if (trace.trace_pgfaults) {
3067 trace.opts.sample_address = true;
3068 trace.opts.sample_time = true;
3069 }
3070
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003071 if (trace.opts.mmap_pages == UINT_MAX)
3072 mmap_pages_user_set = false;
3073
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003074 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003075 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003076 max_stack_user_set = false;
3077 }
3078
3079#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003080 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003081 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003082 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003083#endif
3084
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003085 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003086 if (!mmap_pages_user_set && geteuid() == 0)
3087 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3088
Milian Wolff566a0882016-04-08 13:34:15 +02003089 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003090 }
Milian Wolff566a0882016-04-08 13:34:15 +02003091
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003092 if (trace.evlist->nr_entries > 0)
3093 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3094
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003095 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3096 return trace__record(&trace, argc-1, &argv[1]);
3097
3098 /* summary_only implies summary option, but don't overwrite summary if set */
3099 if (trace.summary_only)
3100 trace.summary = trace.summary_only;
3101
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003102 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3103 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003104 pr_err("Please specify something to trace.\n");
3105 return -1;
3106 }
3107
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003108 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003109 pr_err("The -e option can't be used with --no-syscalls.\n");
3110 goto out;
3111 }
3112
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003113 if (output_name != NULL) {
3114 err = trace__open_output(&trace, output_name);
3115 if (err < 0) {
3116 perror("failed to create output file");
3117 goto out;
3118 }
3119 }
3120
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003121 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3122
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003123 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003124 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003125 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003126 fprintf(trace.output, "%s", bf);
3127 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003128 }
3129
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003130 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003131 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003132 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003133 fprintf(trace.output, "%s", bf);
3134 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003135 }
3136
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003137 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003138 trace.opts.target.system_wide = true;
3139
David Ahern6810fc92013-08-28 22:29:52 -06003140 if (input_name)
3141 err = trace__replay(&trace);
3142 else
3143 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003144
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003145out_close:
3146 if (output_name != NULL)
3147 fclose(trace.output);
3148out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003149 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003150}