blob: 0c1461416ef12ae958a7237e5af38bd2fd79ac68 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030024#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030025#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060026#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030027#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030028#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060029#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030030#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060031#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030032#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060033#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030034#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060035#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030036#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010037#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070038#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000039#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020040#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030041#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030042#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030043#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030044#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030045
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030046#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030047#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030048#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030049#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030050#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030052#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020053#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030054#include <linux/filter.h>
55#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030060
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030061#include "sane_ctype.h"
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef O_CLOEXEC
64# define O_CLOEXEC 02000000
65#endif
66
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030067#ifndef F_LINUX_SPECIFIC_BASE
68# define F_LINUX_SPECIFIC_BASE 1024
69#endif
70
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030071struct trace {
72 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030073 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030074 struct {
75 int max;
76 struct syscall *table;
77 struct {
78 struct perf_evsel *sys_enter,
79 *sys_exit;
80 } events;
81 } syscalls;
82 struct record_opts opts;
83 struct perf_evlist *evlist;
84 struct machine *host;
85 struct thread *current;
86 u64 base_time;
87 FILE *output;
88 unsigned long nr_events;
89 struct strlist *ev_qualifier;
90 struct {
91 size_t nr;
92 int *entries;
93 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030094 struct {
95 size_t nr;
96 pid_t *entries;
97 } filter_pids;
98 double duration_filter;
99 double runtime_ms;
100 struct {
101 u64 vfs_getname,
102 proc_getname;
103 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300104 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300105 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106 bool not_ev_qualifier;
107 bool live;
108 bool full_time;
109 bool sched;
110 bool multiple_threads;
111 bool summary;
112 bool summary_only;
113 bool show_comm;
114 bool show_tool_stats;
115 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300116 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117 bool force;
118 bool vfs_getname;
119 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300120 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300122
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300123struct tp_field {
124 int offset;
125 union {
126 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
127 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
128 };
129};
130
131#define TP_UINT_FIELD(bits) \
132static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
133{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500134 u##bits value; \
135 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
136 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300137}
138
139TP_UINT_FIELD(8);
140TP_UINT_FIELD(16);
141TP_UINT_FIELD(32);
142TP_UINT_FIELD(64);
143
144#define TP_UINT_FIELD__SWAPPED(bits) \
145static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
146{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500147 u##bits value; \
148 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300149 return bswap_##bits(value);\
150}
151
152TP_UINT_FIELD__SWAPPED(16);
153TP_UINT_FIELD__SWAPPED(32);
154TP_UINT_FIELD__SWAPPED(64);
155
156static int tp_field__init_uint(struct tp_field *field,
157 struct format_field *format_field,
158 bool needs_swap)
159{
160 field->offset = format_field->offset;
161
162 switch (format_field->size) {
163 case 1:
164 field->integer = tp_field__u8;
165 break;
166 case 2:
167 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
168 break;
169 case 4:
170 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
171 break;
172 case 8:
173 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
174 break;
175 default:
176 return -1;
177 }
178
179 return 0;
180}
181
182static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
183{
184 return sample->raw_data + field->offset;
185}
186
187static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
188{
189 field->offset = format_field->offset;
190 field->pointer = tp_field__ptr;
191 return 0;
192}
193
194struct syscall_tp {
195 struct tp_field id;
196 union {
197 struct tp_field args, ret;
198 };
199};
200
201static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
202 struct tp_field *field,
203 const char *name)
204{
205 struct format_field *format_field = perf_evsel__field(evsel, name);
206
207 if (format_field == NULL)
208 return -1;
209
210 return tp_field__init_uint(field, format_field, evsel->needs_swap);
211}
212
213#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
214 ({ struct syscall_tp *sc = evsel->priv;\
215 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
216
217static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
218 struct tp_field *field,
219 const char *name)
220{
221 struct format_field *format_field = perf_evsel__field(evsel, name);
222
223 if (format_field == NULL)
224 return -1;
225
226 return tp_field__init_ptr(field, format_field);
227}
228
229#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
230 ({ struct syscall_tp *sc = evsel->priv;\
231 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
232
233static void perf_evsel__delete_priv(struct perf_evsel *evsel)
234{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300235 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300236 perf_evsel__delete(evsel);
237}
238
Namhyung Kim96695d42013-11-12 08:51:45 -0300239static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
240{
241 evsel->priv = malloc(sizeof(struct syscall_tp));
242 if (evsel->priv != NULL) {
243 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
244 goto out_delete;
245
246 evsel->handler = handler;
247 return 0;
248 }
249
250 return -ENOMEM;
251
252out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300253 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300254 return -ENOENT;
255}
256
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300257static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300258{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300259 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300260
David Ahern9aca7f12013-12-04 19:41:39 -0700261 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200262 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700263 evsel = perf_evsel__newtp("syscalls", direction);
264
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200265 if (IS_ERR(evsel))
266 return NULL;
267
268 if (perf_evsel__init_syscall_tp(evsel, handler))
269 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300270
271 return evsel;
272
273out_delete:
274 perf_evsel__delete_priv(evsel);
275 return NULL;
276}
277
278#define perf_evsel__sc_tp_uint(evsel, name, sample) \
279 ({ struct syscall_tp *fields = evsel->priv; \
280 fields->name.integer(&fields->name, sample); })
281
282#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
283 ({ struct syscall_tp *fields = evsel->priv; \
284 fields->name.pointer(&fields->name, sample); })
285
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300286size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
287{
288 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300289
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300290 if (idx < 0 || idx >= sa->nr_entries)
291 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300292
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300293 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300300 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301}
302
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
307}
308
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309#define SCA_STRARRAY syscall_arg__scnprintf_strarray
310
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300311struct strarrays {
312 int nr_entries;
313 struct strarray **entries;
314};
315
316#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
317 .nr_entries = ARRAY_SIZE(array), \
318 .entries = array, \
319}
320
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300321size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
322 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300323{
324 struct strarrays *sas = arg->parm;
325 int i;
326
327 for (i = 0; i < sas->nr_entries; ++i) {
328 struct strarray *sa = sas->entries[i];
329 int idx = arg->val - sa->offset;
330
331 if (idx >= 0 && idx < sa->nr_entries) {
332 if (sa->entries[idx] == NULL)
333 break;
334 return scnprintf(bf, size, "%s", sa->entries[idx]);
335 }
336 }
337
338 return scnprintf(bf, size, "%d", arg->val);
339}
340
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300341#ifndef AT_FDCWD
342#define AT_FDCWD -100
343#endif
344
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300345static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
346 struct syscall_arg *arg)
347{
348 int fd = arg->val;
349
350 if (fd == AT_FDCWD)
351 return scnprintf(bf, size, "CWD");
352
353 return syscall_arg__scnprintf_fd(bf, size, arg);
354}
355
356#define SCA_FDAT syscall_arg__scnprintf_fd_at
357
358static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
359 struct syscall_arg *arg);
360
361#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
362
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300363size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300364{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300365 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300366}
367
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300368size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300369{
370 return scnprintf(bf, size, "%d", arg->val);
371}
372
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300373size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
374{
375 return scnprintf(bf, size, "%ld", arg->val);
376}
377
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300378static const char *bpf_cmd[] = {
379 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
380 "MAP_GET_NEXT_KEY", "PROG_LOAD",
381};
382static DEFINE_STRARRAY(bpf_cmd);
383
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300384static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
385static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300386
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300387static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
388static DEFINE_STRARRAY(itimers);
389
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300390static const char *keyctl_options[] = {
391 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
392 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
393 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
394 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
395 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
396};
397static DEFINE_STRARRAY(keyctl_options);
398
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300399static const char *whences[] = { "SET", "CUR", "END",
400#ifdef SEEK_DATA
401"DATA",
402#endif
403#ifdef SEEK_HOLE
404"HOLE",
405#endif
406};
407static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300408
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300409static const char *fcntl_cmds[] = {
410 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300411 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
412 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
413 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300414};
415static DEFINE_STRARRAY(fcntl_cmds);
416
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300417static const char *fcntl_linux_specific_cmds[] = {
418 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
419 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300420 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300421};
422
423static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
424
425static struct strarray *fcntl_cmds_arrays[] = {
426 &strarray__fcntl_cmds,
427 &strarray__fcntl_linux_specific_cmds,
428};
429
430static DEFINE_STRARRAYS(fcntl_cmds_arrays);
431
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300432static const char *rlimit_resources[] = {
433 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
434 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
435 "RTTIME",
436};
437static DEFINE_STRARRAY(rlimit_resources);
438
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300439static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
440static DEFINE_STRARRAY(sighow);
441
David Ahern4f8c1b72013-09-22 19:45:00 -0600442static const char *clockid[] = {
443 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300444 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
445 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600446};
447static DEFINE_STRARRAY(clockid);
448
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300449static const char *socket_families[] = {
450 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
451 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
452 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
453 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
454 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
455 "ALG", "NFC", "VSOCK",
456};
457static DEFINE_STRARRAY(socket_families);
458
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300459static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
460 struct syscall_arg *arg)
461{
462 size_t printed = 0;
463 int mode = arg->val;
464
465 if (mode == F_OK) /* 0 */
466 return scnprintf(bf, size, "F");
467#define P_MODE(n) \
468 if (mode & n##_OK) { \
469 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
470 mode &= ~n##_OK; \
471 }
472
473 P_MODE(R);
474 P_MODE(W);
475 P_MODE(X);
476#undef P_MODE
477
478 if (mode)
479 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
480
481 return printed;
482}
483
484#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
485
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300486static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
487 struct syscall_arg *arg);
488
489#define SCA_FILENAME syscall_arg__scnprintf_filename
490
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300491static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
492 struct syscall_arg *arg)
493{
494 int printed = 0, flags = arg->val;
495
496#define P_FLAG(n) \
497 if (flags & O_##n) { \
498 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
499 flags &= ~O_##n; \
500 }
501
502 P_FLAG(CLOEXEC);
503 P_FLAG(NONBLOCK);
504#undef P_FLAG
505
506 if (flags)
507 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
508
509 return printed;
510}
511
512#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
513
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300514#ifndef GRND_NONBLOCK
515#define GRND_NONBLOCK 0x0001
516#endif
517#ifndef GRND_RANDOM
518#define GRND_RANDOM 0x0002
519#endif
520
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300521static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
522 struct syscall_arg *arg)
523{
524 int printed = 0, flags = arg->val;
525
526#define P_FLAG(n) \
527 if (flags & GRND_##n) { \
528 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
529 flags &= ~GRND_##n; \
530 }
531
532 P_FLAG(RANDOM);
533 P_FLAG(NONBLOCK);
534#undef P_FLAG
535
536 if (flags)
537 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
538
539 return printed;
540}
541
542#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
543
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300544#define STRARRAY(name, array) \
545 { .scnprintf = SCA_STRARRAY, \
546 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300547
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300548#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300549#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300550#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300551#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300552#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300553#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300554#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300555#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300556#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300557#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300558#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300559#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300560#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300561#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300562
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300563struct syscall_arg_fmt {
564 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
565 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300566 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300567 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300568};
569
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300570static struct syscall_fmt {
571 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300572 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300573 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300574 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300575 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300576 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300577 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300578} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300579 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300580 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300581 { .name = "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 Melo1f631392017-07-18 12:45:57 -0300625 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300626 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300627#if defined(__i386__) || defined(__x86_64__)
628/*
629 * FIXME: Make this available to all arches.
630 */
Arnaldo Carvalho de Melo1cc47f2d2017-07-31 13:20:14 -0300631 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300632 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300633#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300634 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300635#endif
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300636 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300638 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300639 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300640 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300641 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300642 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300643 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300644 { .name = "lstat", .alias = "newlstat", },
645 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300646 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
647 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300648 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300649 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300650 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300651 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300652 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300654 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300655 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300656 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200657/* The standard mmap maps to old_mmap on s390x */
658#if defined(__s390x__)
659 .alias = "old_mmap",
660#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300661 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
662 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
663 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300664 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300665 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
666 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300667 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300668 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300669 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300670 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
671 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
672 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300673 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300674 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300675 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300676 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300677 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300678 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300679 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300680 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300681 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300683 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300684 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
685 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300686 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
688 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300689 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300690 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
691 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
692 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300693 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300694 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300695 { .name = "pkey_alloc",
696 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
697 { .name = "pkey_free",
698 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
699 { .name = "pkey_mprotect",
700 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
701 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
702 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "poll", .timeout = true, },
704 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300705 { .name = "prctl", .alias = "arch_prctl",
706 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
707 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
708 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "pread", .alias = "pread64", },
710 { .name = "preadv", .alias = "pread", },
711 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "pwrite", .alias = "pwrite64", },
714 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300715 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300716 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300717 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300718 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300719 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300720 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300721 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300722 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300723 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300724 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300725 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300726 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300727 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300728 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300729 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300730 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300731 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300732 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300733 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300734 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300735 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
736 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300737 { .name = "select", .timeout = true, },
738 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300744 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300745 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300746 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300747 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300748 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300750 .arg = { [0] = STRARRAY(family, socket_families),
751 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [0] = STRARRAY(family, socket_families),
754 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300755 { .name = "stat", .alias = "newstat", },
756 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300757 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
758 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
759 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300760 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300761 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300764 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300765 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300766 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300768 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300769 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300770 { .name = "uname", .alias = "newuname", },
771 { .name = "unlinkat",
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 = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300774 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300775 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300776 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300777 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300778 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300779};
780
781static int syscall_fmt__cmp(const void *name, const void *fmtp)
782{
783 const struct syscall_fmt *fmt = fmtp;
784 return strcmp(name, fmt->name);
785}
786
787static struct syscall_fmt *syscall_fmt__find(const char *name)
788{
789 const int nmemb = ARRAY_SIZE(syscall_fmts);
790 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
791}
792
793struct syscall {
794 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300795 int nr_args;
796 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300797 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300798 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300799 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300800 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300801};
802
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300803/*
804 * We need to have this 'calculated' boolean because in some cases we really
805 * don't know what is the duration of a syscall, for instance, when we start
806 * a session and some threads are waiting for a syscall to finish, say 'poll',
807 * in which case all we can do is to print "( ? ) for duration and for the
808 * start timestamp.
809 */
810static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200811{
812 double duration = (double)t / NSEC_PER_MSEC;
813 size_t printed = fprintf(fp, "(");
814
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300815 if (!calculated)
816 printed += fprintf(fp, " ? ");
817 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200818 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
819 else if (duration >= 0.01)
820 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
821 else
822 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300823 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200824}
825
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300826/**
827 * filename.ptr: The filename char pointer that will be vfs_getname'd
828 * filename.entry_str_pos: Where to insert the string translated from
829 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300830 * ret_scnprintf: syscall args may set this to a different syscall return
831 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300832 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300833struct thread_trace {
834 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300835 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300836 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400837 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300838 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300839 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300840 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300841 struct {
842 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300843 short int entry_str_pos;
844 bool pending_open;
845 unsigned int namelen;
846 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300847 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300848 struct {
849 int max;
850 char **table;
851 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600852
853 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300854};
855
856static struct thread_trace *thread_trace__new(void)
857{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300858 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
859
860 if (ttrace)
861 ttrace->paths.max = -1;
862
David Ahernbf2575c2013-10-08 21:26:53 -0600863 ttrace->syscall_stats = intlist__new(NULL);
864
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300865 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300866}
867
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300868static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300869{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300870 struct thread_trace *ttrace;
871
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300872 if (thread == NULL)
873 goto fail;
874
Namhyung Kim89dceb22014-10-06 09:46:03 +0900875 if (thread__priv(thread) == NULL)
876 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300877
Namhyung Kim89dceb22014-10-06 09:46:03 +0900878 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300879 goto fail;
880
Namhyung Kim89dceb22014-10-06 09:46:03 +0900881 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300882 ++ttrace->nr_events;
883
884 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300885fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300886 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300887 "WARNING: not enough memory, dropping samples!\n");
888 return NULL;
889}
890
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300891
892void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300893 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300894{
895 struct thread_trace *ttrace = thread__priv(arg->thread);
896
897 ttrace->ret_scnprintf = ret_scnprintf;
898}
899
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400900#define TRACE_PFMAJ (1 << 0)
901#define TRACE_PFMIN (1 << 1)
902
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300903static const size_t trace__entry_str_size = 2048;
904
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300905static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300906{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900907 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908
909 if (fd > ttrace->paths.max) {
910 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
911
912 if (npath == NULL)
913 return -1;
914
915 if (ttrace->paths.max != -1) {
916 memset(npath + ttrace->paths.max + 1, 0,
917 (fd - ttrace->paths.max) * sizeof(char *));
918 } else {
919 memset(npath, 0, (fd + 1) * sizeof(char *));
920 }
921
922 ttrace->paths.table = npath;
923 ttrace->paths.max = fd;
924 }
925
926 ttrace->paths.table[fd] = strdup(pathname);
927
928 return ttrace->paths.table[fd] != NULL ? 0 : -1;
929}
930
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300931static int thread__read_fd_path(struct thread *thread, int fd)
932{
933 char linkname[PATH_MAX], pathname[PATH_MAX];
934 struct stat st;
935 int ret;
936
937 if (thread->pid_ == thread->tid) {
938 scnprintf(linkname, sizeof(linkname),
939 "/proc/%d/fd/%d", thread->pid_, fd);
940 } else {
941 scnprintf(linkname, sizeof(linkname),
942 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
943 }
944
945 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
946 return -1;
947
948 ret = readlink(linkname, pathname, sizeof(pathname));
949
950 if (ret < 0 || ret > st.st_size)
951 return -1;
952
953 pathname[ret] = '\0';
954 return trace__set_fd_pathname(thread, fd, pathname);
955}
956
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300957static const char *thread__fd_path(struct thread *thread, int fd,
958 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300959{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900960 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300961
962 if (ttrace == NULL)
963 return NULL;
964
965 if (fd < 0)
966 return NULL;
967
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300968 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300969 if (!trace->live)
970 return NULL;
971 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300972 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300973 return NULL;
974 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975
976 return ttrace->paths.table[fd];
977}
978
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -0300979size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300980{
981 int fd = arg->val;
982 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300983 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984
985 if (path)
986 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
987
988 return printed;
989}
990
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -0300991size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
992{
993 size_t printed = scnprintf(bf, size, "%d", fd);
994 struct thread *thread = machine__find_thread(trace->host, pid, pid);
995
996 if (thread) {
997 const char *path = thread__fd_path(thread, fd, trace);
998
999 if (path)
1000 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1001
1002 thread__put(thread);
1003 }
1004
1005 return printed;
1006}
1007
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001008static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1009 struct syscall_arg *arg)
1010{
1011 int fd = arg->val;
1012 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001013 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001014
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001015 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1016 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001017
1018 return printed;
1019}
1020
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001021static void thread__set_filename_pos(struct thread *thread, const char *bf,
1022 unsigned long ptr)
1023{
1024 struct thread_trace *ttrace = thread__priv(thread);
1025
1026 ttrace->filename.ptr = ptr;
1027 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1028}
1029
1030static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1031 struct syscall_arg *arg)
1032{
1033 unsigned long ptr = arg->val;
1034
1035 if (!arg->trace->vfs_getname)
1036 return scnprintf(bf, size, "%#x", ptr);
1037
1038 thread__set_filename_pos(arg->thread, bf, ptr);
1039 return 0;
1040}
1041
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001042static bool trace__filter_duration(struct trace *trace, double t)
1043{
1044 return t < (trace->duration_filter * NSEC_PER_MSEC);
1045}
1046
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001047static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001048{
1049 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1050
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001051 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001052}
1053
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001054/*
1055 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1056 * using ttrace->entry_time for a thread that receives a sys_exit without
1057 * first having received a sys_enter ("poll" issued before tracing session
1058 * starts, lost sys_enter exit due to ring buffer overflow).
1059 */
1060static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1061{
1062 if (tstamp > 0)
1063 return __trace__fprintf_tstamp(trace, tstamp, fp);
1064
1065 return fprintf(fp, " ? ");
1066}
1067
Namhyung Kimf15eb532012-10-05 14:02:16 +09001068static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001069static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001070
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001071static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001072{
1073 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001074 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001075}
1076
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001077static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001078 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001079{
1080 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001081 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001082
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001083 if (trace->multiple_threads) {
1084 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001085 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001086 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001087 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001088
1089 return printed;
1090}
1091
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001092static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001093 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094{
1095 int ret = 0;
1096
1097 switch (event->header.type) {
1098 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001099 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001101 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001102 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001103 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001104 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105 break;
1106 }
1107
1108 return ret;
1109}
1110
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001111static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001112 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001113 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001114 struct machine *machine)
1115{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001116 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001117 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001118}
1119
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001120static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1121{
1122 struct machine *machine = vmachine;
1123
1124 if (machine->kptr_restrict_warned)
1125 return NULL;
1126
1127 if (symbol_conf.kptr_restrict) {
1128 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1129 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1130 "Kernel samples will not be resolved.\n");
1131 machine->kptr_restrict_warned = true;
1132 return NULL;
1133 }
1134
1135 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1136}
1137
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001138static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1139{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001140 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001141
1142 if (err)
1143 return err;
1144
David Ahern8fb598e2013-09-28 13:13:00 -06001145 trace->host = machine__new_host();
1146 if (trace->host == NULL)
1147 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001149 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001150 return -errno;
1151
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001152 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001153 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001154 trace->opts.proc_map_timeout, 1);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155 if (err)
1156 symbol__exit();
1157
1158 return err;
1159}
1160
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001161static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1162{
1163 int idx;
1164
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001165 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1166 nr_args = sc->fmt->nr_args;
1167
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001168 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1169 if (sc->arg_fmt == NULL)
1170 return -1;
1171
1172 for (idx = 0; idx < nr_args; ++idx) {
1173 if (sc->fmt)
1174 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1175 }
1176
1177 sc->nr_args = nr_args;
1178 return 0;
1179}
1180
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001181static int syscall__set_arg_fmts(struct syscall *sc)
1182{
1183 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001184 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001185
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001186 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001187 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1188 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001189
1190 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001191 (strcmp(field->name, "filename") == 0 ||
1192 strcmp(field->name, "path") == 0 ||
1193 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001194 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001195 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001196 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001197 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001198 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001199 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001200 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001201 else if ((strcmp(field->type, "int") == 0 ||
1202 strcmp(field->type, "unsigned int") == 0 ||
1203 strcmp(field->type, "long") == 0) &&
1204 (len = strlen(field->name)) >= 2 &&
1205 strcmp(field->name + len - 2, "fd") == 0) {
1206 /*
1207 * /sys/kernel/tracing/events/syscalls/sys_enter*
1208 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1209 * 65 int
1210 * 23 unsigned int
1211 * 7 unsigned long
1212 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001213 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001214 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001215 }
1216
1217 return 0;
1218}
1219
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001220static int trace__read_syscall_info(struct trace *trace, int id)
1221{
1222 char tp_name[128];
1223 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001224 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001225
1226 if (name == NULL)
1227 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001228
1229 if (id > trace->syscalls.max) {
1230 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1231
1232 if (nsyscalls == NULL)
1233 return -1;
1234
1235 if (trace->syscalls.max != -1) {
1236 memset(nsyscalls + trace->syscalls.max + 1, 0,
1237 (id - trace->syscalls.max) * sizeof(*sc));
1238 } else {
1239 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1240 }
1241
1242 trace->syscalls.table = nsyscalls;
1243 trace->syscalls.max = id;
1244 }
1245
1246 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001247 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001248
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001249 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001250
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001251 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001252 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001253
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001254 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001255 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001256 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001257 }
1258
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001259 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1260 return -1;
1261
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001262 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001263 return -1;
1264
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001265 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001266 /*
1267 * We need to check and discard the first variable '__syscall_nr'
1268 * or 'nr' that mean the syscall number. It is needless here.
1269 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1270 */
1271 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001272 sc->args = sc->args->next;
1273 --sc->nr_args;
1274 }
1275
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001276 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1277
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001278 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001279}
1280
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001281static int trace__validate_ev_qualifier(struct trace *trace)
1282{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001283 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001284 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001285 struct str_node *pos;
1286
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001287 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1288 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1289 sizeof(trace->ev_qualifier_ids.entries[0]));
1290
1291 if (trace->ev_qualifier_ids.entries == NULL) {
1292 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1293 trace->output);
1294 err = -EINVAL;
1295 goto out;
1296 }
1297
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001298 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001299 i = 0;
1300
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001301 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001302 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001303 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001304
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001305 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001306 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1307 if (id >= 0)
1308 goto matches;
1309
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001310 if (err == 0) {
1311 fputs("Error:\tInvalid syscall ", trace->output);
1312 err = -EINVAL;
1313 } else {
1314 fputs(", ", trace->output);
1315 }
1316
1317 fputs(sc, trace->output);
1318 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001319matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001320 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001321 if (match_next == -1)
1322 continue;
1323
1324 while (1) {
1325 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1326 if (id < 0)
1327 break;
1328 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1329 void *entries;
1330
1331 nr_allocated += 8;
1332 entries = realloc(trace->ev_qualifier_ids.entries,
1333 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1334 if (entries == NULL) {
1335 err = -ENOMEM;
1336 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1337 goto out_free;
1338 }
1339 trace->ev_qualifier_ids.entries = entries;
1340 }
1341 trace->ev_qualifier_ids.nr++;
1342 trace->ev_qualifier_ids.entries[i++] = id;
1343 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001344 }
1345
1346 if (err < 0) {
1347 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1348 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001349out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001350 zfree(&trace->ev_qualifier_ids.entries);
1351 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001352 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001353out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001354 return err;
1355}
1356
David Ahern55d43bca2015-02-19 15:00:22 -05001357/*
1358 * args is to be interpreted as a series of longs but we need to handle
1359 * 8-byte unaligned accesses. args points to raw_data within the event
1360 * and raw_data is guaranteed to be 8-byte unaligned because it is
1361 * preceded by raw_size which is a u32. So we need to copy args to a temp
1362 * variable to read it. Most notably this avoids extended load instructions
1363 * on unaligned addresses
1364 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001365unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001366{
1367 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001368 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001369
1370 memcpy(&val, p, sizeof(val));
1371 return val;
1372}
1373
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001374static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1375 struct syscall_arg *arg)
1376{
1377 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1378 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1379
1380 return scnprintf(bf, size, "arg%d: ", arg->idx);
1381}
1382
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001383static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1384 struct syscall_arg *arg, unsigned long val)
1385{
1386 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1387 arg->val = val;
1388 if (sc->arg_fmt[arg->idx].parm)
1389 arg->parm = sc->arg_fmt[arg->idx].parm;
1390 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1391 }
1392 return scnprintf(bf, size, "%ld", val);
1393}
1394
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001395static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001396 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001397 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001398{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001399 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001400 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001401 u8 bit = 1;
1402 struct syscall_arg arg = {
1403 .args = args,
1404 .idx = 0,
1405 .mask = 0,
1406 .trace = trace,
1407 .thread = thread,
1408 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001409 struct thread_trace *ttrace = thread__priv(thread);
1410
1411 /*
1412 * Things like fcntl will set this in its 'cmd' formatter to pick the
1413 * right formatter for the return value (an fd? file flags?), which is
1414 * not needed for syscalls that always return a given type, say an fd.
1415 */
1416 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001417
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001418 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001419 struct format_field *field;
1420
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001421 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001422 field = field->next, ++arg.idx, bit <<= 1) {
1423 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001424 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001425
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001426 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001427
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001428 /*
1429 * Suppress this argument if its value is zero and
1430 * and we don't have a string associated in an
1431 * strarray for it.
1432 */
David Ahern55d43bca2015-02-19 15:00:22 -05001433 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001434 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001435 (sc->arg_fmt[arg.idx].show_zero ||
1436 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001437 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1438 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001439 continue;
1440
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001441 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001442 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001443 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001444 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001445 } else if (IS_ERR(sc->tp_format)) {
1446 /*
1447 * If we managed to read the tracepoint /format file, then we
1448 * may end up not having any args, like with gettid(), so only
1449 * print the raw args when we didn't manage to read it.
1450 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001451 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001452 if (arg.mask & bit)
1453 goto next_arg;
1454 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001455 if (printed)
1456 printed += scnprintf(bf + printed, size - printed, ", ");
1457 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001458 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1459next_arg:
1460 ++arg.idx;
1461 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001462 }
1463 }
1464
1465 return printed;
1466}
1467
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001468typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001469 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001470 struct perf_sample *sample);
1471
1472static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001473 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001474{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001475
1476 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001477
1478 /*
1479 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1480 * before that, leaving at a higher verbosity level till that is
1481 * explained. Reproduced with plain ftrace with:
1482 *
1483 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1484 * grep "NR -1 " /t/trace_pipe
1485 *
1486 * After generating some load on the machine.
1487 */
1488 if (verbose > 1) {
1489 static u64 n;
1490 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1491 id, perf_evsel__name(evsel), ++n);
1492 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001493 return NULL;
1494 }
1495
1496 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1497 trace__read_syscall_info(trace, id))
1498 goto out_cant_read;
1499
1500 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1501 goto out_cant_read;
1502
1503 return &trace->syscalls.table[id];
1504
1505out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001506 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001507 fprintf(trace->output, "Problems reading syscall %d", id);
1508 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1509 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1510 fputs(" information\n", trace->output);
1511 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001512 return NULL;
1513}
1514
David Ahernbf2575c2013-10-08 21:26:53 -06001515static void thread__update_stats(struct thread_trace *ttrace,
1516 int id, struct perf_sample *sample)
1517{
1518 struct int_node *inode;
1519 struct stats *stats;
1520 u64 duration = 0;
1521
1522 inode = intlist__findnew(ttrace->syscall_stats, id);
1523 if (inode == NULL)
1524 return;
1525
1526 stats = inode->priv;
1527 if (stats == NULL) {
1528 stats = malloc(sizeof(struct stats));
1529 if (stats == NULL)
1530 return;
1531 init_stats(stats);
1532 inode->priv = stats;
1533 }
1534
1535 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1536 duration = sample->time - ttrace->entry_time;
1537
1538 update_stats(stats, duration);
1539}
1540
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001541static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1542{
1543 struct thread_trace *ttrace;
1544 u64 duration;
1545 size_t printed;
1546
1547 if (trace->current == NULL)
1548 return 0;
1549
1550 ttrace = thread__priv(trace->current);
1551
1552 if (!ttrace->entry_pending)
1553 return 0;
1554
1555 duration = sample->time - ttrace->entry_time;
1556
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001557 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001558 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1559 ttrace->entry_pending = false;
1560
1561 return printed;
1562}
1563
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001564static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001565 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001566 struct perf_sample *sample)
1567{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001568 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001569 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001570 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001571 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001572 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001573 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001574 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001575
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001576 if (sc == NULL)
1577 return -1;
1578
David Ahern8fb598e2013-09-28 13:13:00 -06001579 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001580 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001581 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001582 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001583
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001584 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001585
1586 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001587 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001588 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001589 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001590 }
1591
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001592 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001593 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001594
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001595 ttrace->entry_time = sample->time;
1596 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001597 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001598
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001599 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001600 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001601
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001602 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001603 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001604 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001605 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001606 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001607 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001608 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001609 /* See trace__vfs_getname & trace__sys_exit */
1610 ttrace->filename.pending_open = false;
1611 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001612
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001613 if (trace->current != thread) {
1614 thread__put(trace->current);
1615 trace->current = thread__get(thread);
1616 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001617 err = 0;
1618out_put:
1619 thread__put(thread);
1620 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001621}
1622
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001623static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1624 struct perf_sample *sample,
1625 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001626{
1627 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001628
1629 if (machine__resolve(trace->host, &al, sample) < 0 ||
1630 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1631 return -1;
1632
1633 return 0;
1634}
1635
1636static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1637{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001638 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001639 const unsigned int print_opts = EVSEL__PRINT_SYM |
1640 EVSEL__PRINT_DSO |
1641 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001642
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001643 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001644}
1645
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001646static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001647 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001648 struct perf_sample *sample)
1649{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001650 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001651 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001652 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001653 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001654 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001655 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001656 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001657
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001658 if (sc == NULL)
1659 return -1;
1660
David Ahern8fb598e2013-09-28 13:13:00 -06001661 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001662 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001663 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001664 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001665
David Ahernbf2575c2013-10-08 21:26:53 -06001666 if (trace->summary)
1667 thread__update_stats(ttrace, id, sample);
1668
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001669 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001670
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001671 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001672 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1673 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001674 ++trace->stats.vfs_getname;
1675 }
1676
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001677 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001678 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001679 if (trace__filter_duration(trace, duration))
1680 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001681 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001682 } else if (trace->duration_filter)
1683 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001684
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001685 if (sample->callchain) {
1686 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1687 if (callchain_ret == 0) {
1688 if (callchain_cursor.nr < trace->min_stack)
1689 goto out;
1690 callchain_ret = 1;
1691 }
1692 }
1693
David Ahernfd2eaba2013-11-12 09:31:15 -07001694 if (trace->summary_only)
1695 goto out;
1696
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001697 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001698
1699 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001700 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001701 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001702 fprintf(trace->output, " ... [");
1703 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1704 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001705 }
1706
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001707 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001708 if (ret < 0)
1709 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001710signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001711 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001712 } else if (ret < 0) {
1713errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001714 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001715 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001716 *e = audit_errno_to_name(-ret);
1717
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001718 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001719 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001720 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001721 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001722 else if (ttrace->ret_scnprintf) {
1723 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001724 struct syscall_arg arg = {
1725 .val = ret,
1726 .thread = thread,
1727 .trace = trace,
1728 };
1729 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001730 ttrace->ret_scnprintf = NULL;
1731 fprintf(trace->output, ") = %s", bf);
1732 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001733 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001734 else if (sc->fmt->errpid) {
1735 struct thread *child = machine__find_thread(trace->host, ret, ret);
1736
1737 if (child != NULL) {
1738 fprintf(trace->output, ") = %ld", ret);
1739 if (child->comm_set)
1740 fprintf(trace->output, " (%s)", thread__comm_str(child));
1741 thread__put(child);
1742 }
1743 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001744 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001745
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001746 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001747
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001748 if (callchain_ret > 0)
1749 trace__fprintf_callchain(trace, sample);
1750 else if (callchain_ret < 0)
1751 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001752out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001753 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001754 err = 0;
1755out_put:
1756 thread__put(thread);
1757 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001758}
1759
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001760static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001761 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001762 struct perf_sample *sample)
1763{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001764 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1765 struct thread_trace *ttrace;
1766 size_t filename_len, entry_str_len, to_move;
1767 ssize_t remaining_space;
1768 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001769 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001770
1771 if (!thread)
1772 goto out;
1773
1774 ttrace = thread__priv(thread);
1775 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001776 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001777
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001778 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001779 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001780 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001781
1782 if (ttrace->filename.namelen < filename_len) {
1783 char *f = realloc(ttrace->filename.name, filename_len + 1);
1784
1785 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001786 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001787
1788 ttrace->filename.namelen = filename_len;
1789 ttrace->filename.name = f;
1790 }
1791
1792 strcpy(ttrace->filename.name, filename);
1793 ttrace->filename.pending_open = true;
1794
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001795 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001796 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001797
1798 entry_str_len = strlen(ttrace->entry_str);
1799 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1800 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001801 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001802
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001803 if (filename_len > (size_t)remaining_space) {
1804 filename += filename_len - remaining_space;
1805 filename_len = remaining_space;
1806 }
1807
1808 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1809 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1810 memmove(pos + filename_len, pos, to_move);
1811 memcpy(pos, filename, filename_len);
1812
1813 ttrace->filename.ptr = 0;
1814 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001815out_put:
1816 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001817out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001818 return 0;
1819}
1820
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001821static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001822 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001823 struct perf_sample *sample)
1824{
1825 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1826 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001827 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001828 sample->pid,
1829 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001830 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001831
1832 if (ttrace == NULL)
1833 goto out_dump;
1834
1835 ttrace->runtime_ms += runtime_ms;
1836 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001837out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001838 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001839 return 0;
1840
1841out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001842 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001843 evsel->name,
1844 perf_evsel__strval(evsel, sample, "comm"),
1845 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1846 runtime,
1847 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001848 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001849}
1850
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001851static int bpf_output__printer(enum binary_printer_ops op,
1852 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001853{
Wang Nan1d6c9402016-02-26 09:31:55 +00001854 unsigned char ch = (unsigned char)val;
1855
1856 switch (op) {
1857 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001858 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001859 case BINARY_PRINT_DATA_BEGIN:
1860 case BINARY_PRINT_LINE_BEGIN:
1861 case BINARY_PRINT_ADDR:
1862 case BINARY_PRINT_NUM_DATA:
1863 case BINARY_PRINT_NUM_PAD:
1864 case BINARY_PRINT_SEP:
1865 case BINARY_PRINT_CHAR_PAD:
1866 case BINARY_PRINT_LINE_END:
1867 case BINARY_PRINT_DATA_END:
1868 default:
1869 break;
1870 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001871
1872 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001873}
1874
1875static void bpf_output__fprintf(struct trace *trace,
1876 struct perf_sample *sample)
1877{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001878 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1879 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001880}
1881
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001882static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1883 union perf_event *event __maybe_unused,
1884 struct perf_sample *sample)
1885{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001886 int callchain_ret = 0;
1887
1888 if (sample->callchain) {
1889 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1890 if (callchain_ret == 0) {
1891 if (callchain_cursor.nr < trace->min_stack)
1892 goto out;
1893 callchain_ret = 1;
1894 }
1895 }
1896
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001897 trace__printf_interrupted_entry(trace, sample);
1898 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001899
1900 if (trace->trace_syscalls)
1901 fprintf(trace->output, "( ): ");
1902
1903 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001904
Wang Nan1d6c9402016-02-26 09:31:55 +00001905 if (perf_evsel__is_bpf_output(evsel)) {
1906 bpf_output__fprintf(trace, sample);
1907 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001908 event_format__fprintf(evsel->tp_format, sample->cpu,
1909 sample->raw_data, sample->raw_size,
1910 trace->output);
1911 }
1912
1913 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001914
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001915 if (callchain_ret > 0)
1916 trace__fprintf_callchain(trace, sample);
1917 else if (callchain_ret < 0)
1918 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1919out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001920 return 0;
1921}
1922
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001923static void print_location(FILE *f, struct perf_sample *sample,
1924 struct addr_location *al,
1925 bool print_dso, bool print_sym)
1926{
1927
Namhyung Kimbb963e12017-02-17 17:17:38 +09001928 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001929 fprintf(f, "%s@", al->map->dso->long_name);
1930
Namhyung Kimbb963e12017-02-17 17:17:38 +09001931 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001932 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001933 al->addr - al->sym->start);
1934 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001935 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001936 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001937 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001938}
1939
1940static int trace__pgfault(struct trace *trace,
1941 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001942 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001943 struct perf_sample *sample)
1944{
1945 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001946 struct addr_location al;
1947 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001948 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001949 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001950 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001951
1952 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001953
1954 if (sample->callchain) {
1955 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1956 if (callchain_ret == 0) {
1957 if (callchain_cursor.nr < trace->min_stack)
1958 goto out_put;
1959 callchain_ret = 1;
1960 }
1961 }
1962
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001963 ttrace = thread__trace(thread, trace->output);
1964 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001965 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001966
1967 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1968 ttrace->pfmaj++;
1969 else
1970 ttrace->pfmin++;
1971
1972 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001973 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001974
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001975 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001976 sample->ip, &al);
1977
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001978 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001979
1980 fprintf(trace->output, "%sfault [",
1981 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1982 "maj" : "min");
1983
1984 print_location(trace->output, sample, &al, false, true);
1985
1986 fprintf(trace->output, "] => ");
1987
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001988 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001989 sample->addr, &al);
1990
1991 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001992 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001993 MAP__FUNCTION, sample->addr, &al);
1994
1995 if (al.map)
1996 map_type = 'x';
1997 else
1998 map_type = '?';
1999 }
2000
2001 print_location(trace->output, sample, &al, true, false);
2002
2003 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002004
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002005 if (callchain_ret > 0)
2006 trace__fprintf_callchain(trace, sample);
2007 else if (callchain_ret < 0)
2008 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002009out:
2010 err = 0;
2011out_put:
2012 thread__put(thread);
2013 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002014}
2015
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002016static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002017 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002018 struct perf_sample *sample)
2019{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002020 /*
2021 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2022 * and don't use sample->time unconditionally, we may end up having
2023 * some other event in the future without PERF_SAMPLE_TIME for good
2024 * reason, i.e. we may not be interested in its timestamps, just in
2025 * it taking place, picking some piece of information when it
2026 * appears in our event stream (vfs_getname comes to mind).
2027 */
2028 if (trace->base_time == 0 && !trace->full_time &&
2029 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002030 trace->base_time = sample->time;
2031}
2032
David Ahern6810fc92013-08-28 22:29:52 -06002033static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002034 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002035 struct perf_sample *sample,
2036 struct perf_evsel *evsel,
2037 struct machine *machine __maybe_unused)
2038{
2039 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002040 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002041 int err = 0;
2042
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002043 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002044
David Ahernaa07df62016-11-25 09:29:52 -07002045 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2046 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002047 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002048
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002049 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002050
David Ahern31605652013-12-04 19:41:41 -07002051 if (handler) {
2052 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002053 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002054 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002055out:
2056 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002057 return err;
2058}
2059
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002060static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002061{
2062 unsigned int rec_argc, i, j;
2063 const char **rec_argv;
2064 const char * const record_args[] = {
2065 "record",
2066 "-R",
2067 "-m", "1024",
2068 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002069 };
2070
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002071 const char * const sc_args[] = { "-e", };
2072 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2073 const char * const majpf_args[] = { "-e", "major-faults" };
2074 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2075 const char * const minpf_args[] = { "-e", "minor-faults" };
2076 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2077
David Ahern9aca7f12013-12-04 19:41:39 -07002078 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002079 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2080 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002081 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2082
2083 if (rec_argv == NULL)
2084 return -ENOMEM;
2085
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002086 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002087 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002088 rec_argv[j++] = record_args[i];
2089
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002090 if (trace->trace_syscalls) {
2091 for (i = 0; i < sc_args_nr; i++)
2092 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002093
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002094 /* event string may be different for older kernels - e.g., RHEL6 */
2095 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2096 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2097 else if (is_valid_tracepoint("syscalls:sys_enter"))
2098 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2099 else {
2100 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002101 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002102 return -1;
2103 }
David Ahern9aca7f12013-12-04 19:41:39 -07002104 }
David Ahern9aca7f12013-12-04 19:41:39 -07002105
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002106 if (trace->trace_pgfaults & TRACE_PFMAJ)
2107 for (i = 0; i < majpf_args_nr; i++)
2108 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002109
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002110 if (trace->trace_pgfaults & TRACE_PFMIN)
2111 for (i = 0; i < minpf_args_nr; i++)
2112 rec_argv[j++] = minpf_args[i];
2113
2114 for (i = 0; i < (unsigned int)argc; i++)
2115 rec_argv[j++] = argv[i];
2116
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002117 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002118}
2119
David Ahernbf2575c2013-10-08 21:26:53 -06002120static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2121
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002122static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002123{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002124 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002125
2126 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002127 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002128
2129 if (perf_evsel__field(evsel, "pathname") == NULL) {
2130 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002131 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002132 }
2133
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002134 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002135 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002136 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002137}
2138
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002139static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002140{
2141 struct perf_evsel *evsel;
2142 struct perf_event_attr attr = {
2143 .type = PERF_TYPE_SOFTWARE,
2144 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002145 };
2146
2147 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002148 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002149
2150 event_attr_init(&attr);
2151
2152 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002153 if (evsel)
2154 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002155
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002156 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002157}
2158
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002159static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2160{
2161 const u32 type = event->header.type;
2162 struct perf_evsel *evsel;
2163
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002164 if (type != PERF_RECORD_SAMPLE) {
2165 trace__process_event(trace, trace->host, event, sample);
2166 return;
2167 }
2168
2169 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2170 if (evsel == NULL) {
2171 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2172 return;
2173 }
2174
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002175 trace__set_base_time(trace, evsel, sample);
2176
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002177 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2178 sample->raw_data == NULL) {
2179 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2180 perf_evsel__name(evsel), sample->tid,
2181 sample->cpu, sample->raw_size);
2182 } else {
2183 tracepoint_handler handler = evsel->handler;
2184 handler(trace, evsel, event, sample);
2185 }
2186}
2187
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002188static int trace__add_syscall_newtp(struct trace *trace)
2189{
2190 int ret = -1;
2191 struct perf_evlist *evlist = trace->evlist;
2192 struct perf_evsel *sys_enter, *sys_exit;
2193
2194 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2195 if (sys_enter == NULL)
2196 goto out;
2197
2198 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2199 goto out_delete_sys_enter;
2200
2201 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2202 if (sys_exit == NULL)
2203 goto out_delete_sys_enter;
2204
2205 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2206 goto out_delete_sys_exit;
2207
2208 perf_evlist__add(evlist, sys_enter);
2209 perf_evlist__add(evlist, sys_exit);
2210
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002211 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002212 /*
2213 * We're interested only in the user space callchain
2214 * leading to the syscall, allow overriding that for
2215 * debugging reasons using --kernel_syscall_callchains
2216 */
2217 sys_exit->attr.exclude_callchain_kernel = 1;
2218 }
2219
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002220 trace->syscalls.events.sys_enter = sys_enter;
2221 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002222
2223 ret = 0;
2224out:
2225 return ret;
2226
2227out_delete_sys_exit:
2228 perf_evsel__delete_priv(sys_exit);
2229out_delete_sys_enter:
2230 perf_evsel__delete_priv(sys_enter);
2231 goto out;
2232}
2233
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002234static int trace__set_ev_qualifier_filter(struct trace *trace)
2235{
2236 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002237 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002238 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2239 trace->ev_qualifier_ids.nr,
2240 trace->ev_qualifier_ids.entries);
2241
2242 if (filter == NULL)
2243 goto out_enomem;
2244
Mathieu Poirier3541c032016-09-16 08:44:04 -06002245 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2246 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002247 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002248 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002249 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002250
2251 free(filter);
2252out:
2253 return err;
2254out_enomem:
2255 errno = ENOMEM;
2256 goto out;
2257}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002258
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002259static int trace__set_filter_loop_pids(struct trace *trace)
2260{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002261 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002262 pid_t pids[32] = {
2263 getpid(),
2264 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002265 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2266
2267 while (thread && nr < ARRAY_SIZE(pids)) {
2268 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2269
2270 if (parent == NULL)
2271 break;
2272
2273 if (!strcmp(thread__comm_str(parent), "sshd")) {
2274 pids[nr++] = parent->tid;
2275 break;
2276 }
2277 thread = parent;
2278 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002279
2280 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2281}
2282
Namhyung Kimf15eb532012-10-05 14:02:16 +09002283static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002284{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002285 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002286 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002287 int err = -1, i;
2288 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002289 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002290 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002291
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002292 trace->live = true;
2293
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002294 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002295 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002296
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002297 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002298 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002299
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002300 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2301 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2302 if (pgfault_maj == NULL)
2303 goto out_error_mem;
2304 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002305 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002306
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002307 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2308 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2309 if (pgfault_min == NULL)
2310 goto out_error_mem;
2311 perf_evlist__add(evlist, pgfault_min);
2312 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002313
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002314 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002315 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2316 trace__sched_stat_runtime))
2317 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002318
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002319 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2320 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002321 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322 goto out_delete_evlist;
2323 }
2324
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002325 err = trace__symbols_init(trace, evlist);
2326 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002327 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002328 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002329 }
2330
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002331 perf_evlist__config(evlist, &trace->opts, NULL);
2332
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002333 if (callchain_param.enabled) {
2334 bool use_identifier = false;
2335
2336 if (trace->syscalls.events.sys_exit) {
2337 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2338 &trace->opts, &callchain_param);
2339 use_identifier = true;
2340 }
2341
2342 if (pgfault_maj) {
2343 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2344 use_identifier = true;
2345 }
2346
2347 if (pgfault_min) {
2348 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2349 use_identifier = true;
2350 }
2351
2352 if (use_identifier) {
2353 /*
2354 * Now we have evsels with different sample_ids, use
2355 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2356 * from a fixed position in each ring buffer record.
2357 *
2358 * As of this the changeset introducing this comment, this
2359 * isn't strictly needed, as the fields that can come before
2360 * PERF_SAMPLE_ID are all used, but we'll probably disable
2361 * some of those for things like copying the payload of
2362 * pointer syscall arguments, and for vfs_getname we don't
2363 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2364 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2365 */
2366 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2367 perf_evlist__reset_sample_bit(evlist, ID);
2368 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002369 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002370
Namhyung Kimf15eb532012-10-05 14:02:16 +09002371 signal(SIGCHLD, sig_handler);
2372 signal(SIGINT, sig_handler);
2373
2374 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002375 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002376 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002377 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002378 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002379 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002380 }
2381 }
2382
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002383 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002384 if (err < 0)
2385 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002386
Wang Nanba504232016-02-26 09:31:54 +00002387 err = bpf__apply_obj_config();
2388 if (err) {
2389 char errbuf[BUFSIZ];
2390
2391 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2392 pr_err("ERROR: Apply config to BPF failed: %s\n",
2393 errbuf);
2394 goto out_error_open;
2395 }
2396
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002397 /*
2398 * Better not use !target__has_task() here because we need to cover the
2399 * case where no threads were specified in the command line, but a
2400 * workload was, and in that case we will fill in the thread_map when
2401 * we fork the workload in perf_evlist__prepare_workload.
2402 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002403 if (trace->filter_pids.nr > 0)
2404 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002405 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002406 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002407
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002408 if (err < 0)
2409 goto out_error_mem;
2410
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002411 if (trace->ev_qualifier_ids.nr > 0) {
2412 err = trace__set_ev_qualifier_filter(trace);
2413 if (err < 0)
2414 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002415
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002416 pr_debug("event qualifier tracepoint filter: %s\n",
2417 trace->syscalls.events.sys_exit->filter);
2418 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002419
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002420 err = perf_evlist__apply_filters(evlist, &evsel);
2421 if (err < 0)
2422 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002423
Jiri Olsaf8850372013-11-28 17:57:22 +01002424 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002425 if (err < 0)
2426 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002427
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002428 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002429 perf_evlist__enable(evlist);
2430
Namhyung Kimf15eb532012-10-05 14:02:16 +09002431 if (forks)
2432 perf_evlist__start_workload(evlist);
2433
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002434 if (trace->opts.initial_delay) {
2435 usleep(trace->opts.initial_delay * 1000);
2436 perf_evlist__enable(evlist);
2437 }
2438
Jiri Olsae13798c2015-06-23 00:36:02 +02002439 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002440 evlist->threads->nr > 1 ||
2441 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002442again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002443 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002444
2445 for (i = 0; i < evlist->nr_mmaps; i++) {
2446 union perf_event *event;
2447
2448 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002449 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002450
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002451 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002452
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002453 err = perf_evlist__parse_sample(evlist, event, &sample);
2454 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002455 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002456 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002457 }
2458
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002459 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002460next_event:
2461 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002462
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002463 if (interrupted)
2464 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002465
2466 if (done && !draining) {
2467 perf_evlist__disable(evlist);
2468 draining = true;
2469 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002470 }
2471 }
2472
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002473 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002474 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002475
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002476 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2477 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2478 draining = true;
2479
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002480 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002481 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002482 } else {
2483 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002484 }
2485
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002486out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002487 thread__zput(trace->current);
2488
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002489 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002490
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002491 if (!err) {
2492 if (trace->summary)
2493 trace__fprintf_thread_summary(trace, trace->output);
2494
2495 if (trace->show_tool_stats) {
2496 fprintf(trace->output, "Stats:\n "
2497 " vfs_getname : %" PRIu64 "\n"
2498 " proc_getname: %" PRIu64 "\n",
2499 trace->stats.vfs_getname,
2500 trace->stats.proc_getname);
2501 }
2502 }
David Ahernbf2575c2013-10-08 21:26:53 -06002503
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002504out_delete_evlist:
2505 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002506 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002507 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002508 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002509{
2510 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002511
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002512out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002513 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002514 goto out_error;
2515
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002516out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002517 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002518 goto out_error;
2519
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002520out_error_mmap:
2521 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2522 goto out_error;
2523
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002524out_error_open:
2525 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2526
2527out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002528 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302529 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002530
2531out_error_apply_filters:
2532 fprintf(trace->output,
2533 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2534 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002535 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002536 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002537}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002538out_error_mem:
2539 fprintf(trace->output, "Not enough memory to run!\n");
2540 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002541
2542out_errno:
2543 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2544 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002545}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002546
David Ahern6810fc92013-08-28 22:29:52 -06002547static int trace__replay(struct trace *trace)
2548{
2549 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002550 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002551 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002552 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002553 .file = {
2554 .path = input_name,
2555 },
2556 .mode = PERF_DATA_MODE_READ,
2557 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002558 };
David Ahern6810fc92013-08-28 22:29:52 -06002559 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002560 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002561 int err = -1;
2562
2563 trace->tool.sample = trace__process_sample;
2564 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002565 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002566 trace->tool.comm = perf_event__process_comm;
2567 trace->tool.exit = perf_event__process_exit;
2568 trace->tool.fork = perf_event__process_fork;
2569 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302570 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002571 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302572 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002573
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002574 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002575 trace->tool.ordering_requires_timestamps = true;
2576
2577 /* add tid to output */
2578 trace->multiple_threads = true;
2579
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002580 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002581 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002582 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002583
David Ahernaa07df62016-11-25 09:29:52 -07002584 if (trace->opts.target.pid)
2585 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2586
2587 if (trace->opts.target.tid)
2588 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2589
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002590 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002591 goto out;
2592
David Ahern8fb598e2013-09-28 13:13:00 -06002593 trace->host = &session->machines.host;
2594
David Ahern6810fc92013-08-28 22:29:52 -06002595 err = perf_session__set_tracepoints_handlers(session, handlers);
2596 if (err)
2597 goto out;
2598
Namhyung Kim003824e2013-11-12 15:25:00 +09002599 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2600 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002601 /* older kernels have syscalls tp versus raw_syscalls */
2602 if (evsel == NULL)
2603 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2604 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002605
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002606 if (evsel &&
2607 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2608 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002609 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2610 goto out;
2611 }
2612
2613 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2614 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002615 if (evsel == NULL)
2616 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2617 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002618 if (evsel &&
2619 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2620 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002621 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002622 goto out;
2623 }
2624
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002625 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002626 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2627 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2628 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2629 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2630 evsel->handler = trace__pgfault;
2631 }
2632
David Ahern6810fc92013-08-28 22:29:52 -06002633 setup_pager();
2634
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002635 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002636 if (err)
2637 pr_err("Failed to process events, error %d", err);
2638
David Ahernbf2575c2013-10-08 21:26:53 -06002639 else if (trace->summary)
2640 trace__fprintf_thread_summary(trace, trace->output);
2641
David Ahern6810fc92013-08-28 22:29:52 -06002642out:
2643 perf_session__delete(session);
2644
2645 return err;
2646}
2647
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002648static size_t trace__fprintf_threads_header(FILE *fp)
2649{
2650 size_t printed;
2651
Pekka Enberg99ff7152013-11-12 16:42:14 +02002652 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002653
2654 return printed;
2655}
2656
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002657DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2658 struct stats *stats;
2659 double msecs;
2660 int syscall;
2661)
2662{
2663 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2664 struct stats *stats = source->priv;
2665
2666 entry->syscall = source->i;
2667 entry->stats = stats;
2668 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2669}
2670
David Ahernbf2575c2013-10-08 21:26:53 -06002671static size_t thread__dump_stats(struct thread_trace *ttrace,
2672 struct trace *trace, FILE *fp)
2673{
David Ahernbf2575c2013-10-08 21:26:53 -06002674 size_t printed = 0;
2675 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002676 struct rb_node *nd;
2677 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002678
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002679 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002680 return 0;
2681
2682 printed += fprintf(fp, "\n");
2683
Milian Wolff834fd462015-08-06 11:24:29 +02002684 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2685 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2686 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002687
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002688 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002689 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002690 if (stats) {
2691 double min = (double)(stats->min) / NSEC_PER_MSEC;
2692 double max = (double)(stats->max) / NSEC_PER_MSEC;
2693 double avg = avg_stats(stats);
2694 double pct;
2695 u64 n = (u64) stats->n;
2696
2697 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2698 avg /= NSEC_PER_MSEC;
2699
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002700 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002701 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002702 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002703 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002704 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002705 }
David Ahernbf2575c2013-10-08 21:26:53 -06002706 }
2707
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002708 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002709 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002710
2711 return printed;
2712}
2713
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002714static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002715{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002716 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002717 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002718 double ratio;
2719
2720 if (ttrace == NULL)
2721 return 0;
2722
2723 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2724
Pekka Enberg15e65c62013-11-14 18:43:30 +02002725 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002726 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002727 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002728 if (ttrace->pfmaj)
2729 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2730 if (ttrace->pfmin)
2731 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002732 if (trace->sched)
2733 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2734 else if (fputc('\n', fp) != EOF)
2735 ++printed;
2736
David Ahernbf2575c2013-10-08 21:26:53 -06002737 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002738
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002739 return printed;
2740}
David Ahern896cbb52013-09-28 13:12:59 -06002741
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002742static unsigned long thread__nr_events(struct thread_trace *ttrace)
2743{
2744 return ttrace ? ttrace->nr_events : 0;
2745}
2746
2747DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2748 struct thread *thread;
2749)
2750{
2751 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002752}
2753
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002754static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2755{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002756 size_t printed = trace__fprintf_threads_header(fp);
2757 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002758 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002759
Kan Liang91e467b2017-09-10 19:23:14 -07002760 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2761 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2762
2763 if (threads == NULL) {
2764 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2765 return 0;
2766 }
2767
2768 resort_rb__for_each_entry(nd, threads)
2769 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2770
2771 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002772 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002773 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002774}
2775
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002776static int trace__set_duration(const struct option *opt, const char *str,
2777 int unset __maybe_unused)
2778{
2779 struct trace *trace = opt->value;
2780
2781 trace->duration_filter = atof(str);
2782 return 0;
2783}
2784
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002785static int trace__set_filter_pids(const struct option *opt, const char *str,
2786 int unset __maybe_unused)
2787{
2788 int ret = -1;
2789 size_t i;
2790 struct trace *trace = opt->value;
2791 /*
2792 * FIXME: introduce a intarray class, plain parse csv and create a
2793 * { int nr, int entries[] } struct...
2794 */
2795 struct intlist *list = intlist__new(str);
2796
2797 if (list == NULL)
2798 return -1;
2799
2800 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2801 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2802
2803 if (trace->filter_pids.entries == NULL)
2804 goto out;
2805
2806 trace->filter_pids.entries[0] = getpid();
2807
2808 for (i = 1; i < trace->filter_pids.nr; ++i)
2809 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2810
2811 intlist__delete(list);
2812 ret = 0;
2813out:
2814 return ret;
2815}
2816
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002817static int trace__open_output(struct trace *trace, const char *filename)
2818{
2819 struct stat st;
2820
2821 if (!stat(filename, &st) && st.st_size) {
2822 char oldname[PATH_MAX];
2823
2824 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2825 unlink(oldname);
2826 rename(filename, oldname);
2827 }
2828
2829 trace->output = fopen(filename, "w");
2830
2831 return trace->output == NULL ? -errno : 0;
2832}
2833
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002834static int parse_pagefaults(const struct option *opt, const char *str,
2835 int unset __maybe_unused)
2836{
2837 int *trace_pgfaults = opt->value;
2838
2839 if (strcmp(str, "all") == 0)
2840 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2841 else if (strcmp(str, "maj") == 0)
2842 *trace_pgfaults |= TRACE_PFMAJ;
2843 else if (strcmp(str, "min") == 0)
2844 *trace_pgfaults |= TRACE_PFMIN;
2845 else
2846 return -1;
2847
2848 return 0;
2849}
2850
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002851static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2852{
2853 struct perf_evsel *evsel;
2854
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002855 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002856 evsel->handler = handler;
2857}
2858
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002859/*
2860 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2861 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2862 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2863 *
2864 * It'd be better to introduce a parse_options() variant that would return a
2865 * list with the terms it didn't match to an event...
2866 */
2867static int trace__parse_events_option(const struct option *opt, const char *str,
2868 int unset __maybe_unused)
2869{
2870 struct trace *trace = (struct trace *)opt->value;
2871 const char *s = str;
2872 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002873 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002874 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2875 char group_name[PATH_MAX];
2876
2877 if (strace_groups_dir == NULL)
2878 return -1;
2879
2880 if (*s == '!') {
2881 ++s;
2882 trace->not_ev_qualifier = true;
2883 }
2884
2885 while (1) {
2886 if ((sep = strchr(s, ',')) != NULL)
2887 *sep = '\0';
2888
2889 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002890 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
2891 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002892 list = 1;
2893 } else {
2894 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2895 if (access(group_name, R_OK) == 0)
2896 list = 1;
2897 }
2898
2899 if (lists[list]) {
2900 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2901 } else {
2902 lists[list] = malloc(len);
2903 if (lists[list] == NULL)
2904 goto out;
2905 strcpy(lists[list], s);
2906 }
2907
2908 if (!sep)
2909 break;
2910
2911 *sep = ',';
2912 s = sep + 1;
2913 }
2914
2915 if (lists[1] != NULL) {
2916 struct strlist_config slist_config = {
2917 .dirname = strace_groups_dir,
2918 };
2919
2920 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2921 if (trace->ev_qualifier == NULL) {
2922 fputs("Not enough memory to parse event qualifier", trace->output);
2923 goto out;
2924 }
2925
2926 if (trace__validate_ev_qualifier(trace))
2927 goto out;
2928 }
2929
2930 err = 0;
2931
2932 if (lists[0]) {
2933 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2934 "event selector. use 'perf list' to list available events",
2935 parse_events_option);
2936 err = parse_events_option(&o, lists[0], 0);
2937 }
2938out:
2939 if (sep)
2940 *sep = ',';
2941
2942 return err;
2943}
2944
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002945int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002946{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002947 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002948 "perf trace [<options>] [<command>]",
2949 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002950 "perf trace record [<options>] [<command>]",
2951 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002952 NULL
2953 };
2954 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002955 .syscalls = {
2956 . max = -1,
2957 },
2958 .opts = {
2959 .target = {
2960 .uid = UINT_MAX,
2961 .uses_mmap = true,
2962 },
2963 .user_freq = UINT_MAX,
2964 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002965 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002966 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002967 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002968 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002969 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002970 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002971 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002972 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002973 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002974 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002975 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002976 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002977 OPT_CALLBACK('e', "event", &trace, "event",
2978 "event/syscall selector. use 'perf list' to list available events",
2979 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002980 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2981 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002982 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002983 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2984 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002985 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002986 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002987 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2988 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002989 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002990 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002991 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2992 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002993 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002994 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002995 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002996 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002997 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002998 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002999 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3000 "number of mmap data pages",
3001 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003002 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003003 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003004 OPT_CALLBACK(0, "duration", &trace, "float",
3005 "show only events with duration > N.M ms",
3006 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003007 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003008 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003009 OPT_BOOLEAN('T', "time", &trace.full_time,
3010 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003011 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3012 "Show only syscall summary with statistics"),
3013 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3014 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003015 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3016 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003017 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003018 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003019 OPT_CALLBACK(0, "call-graph", &trace.opts,
3020 "record_mode[,record_size]", record_callchain_help,
3021 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003022 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3023 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003024 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3025 "Set the minimum stack depth when parsing the callchain, "
3026 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003027 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3028 "Set the maximum stack depth when parsing the callchain, "
3029 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003030 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003031 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3032 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003033 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3034 "ms to wait before starting measurement after program "
3035 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003036 OPT_END()
3037 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003038 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003039 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003040 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003041 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003042 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003043
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003044 signal(SIGSEGV, sighandler_dump_stack);
3045 signal(SIGFPE, sighandler_dump_stack);
3046
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003047 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003048 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003049
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003050 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003051 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003052 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003053 goto out;
3054 }
3055
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003056 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3057 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003058
Wang Nand7888572016-04-08 15:07:24 +00003059 err = bpf__setup_stdout(trace.evlist);
3060 if (err) {
3061 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3062 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3063 goto out;
3064 }
3065
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003066 err = -1;
3067
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003068 if (trace.trace_pgfaults) {
3069 trace.opts.sample_address = true;
3070 trace.opts.sample_time = true;
3071 }
3072
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003073 if (trace.opts.mmap_pages == UINT_MAX)
3074 mmap_pages_user_set = false;
3075
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003076 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003077 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003078 max_stack_user_set = false;
3079 }
3080
3081#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003082 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003083 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3084#endif
3085
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003086 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003087 if (!mmap_pages_user_set && geteuid() == 0)
3088 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3089
Milian Wolff566a0882016-04-08 13:34:15 +02003090 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003091 }
Milian Wolff566a0882016-04-08 13:34:15 +02003092
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003093 if (trace.evlist->nr_entries > 0)
3094 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3095
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003096 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3097 return trace__record(&trace, argc-1, &argv[1]);
3098
3099 /* summary_only implies summary option, but don't overwrite summary if set */
3100 if (trace.summary_only)
3101 trace.summary = trace.summary_only;
3102
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003103 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3104 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003105 pr_err("Please specify something to trace.\n");
3106 return -1;
3107 }
3108
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003109 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003110 pr_err("The -e option can't be used with --no-syscalls.\n");
3111 goto out;
3112 }
3113
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003114 if (output_name != NULL) {
3115 err = trace__open_output(&trace, output_name);
3116 if (err < 0) {
3117 perror("failed to create output file");
3118 goto out;
3119 }
3120 }
3121
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003122 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3123
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003124 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003125 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003126 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003127 fprintf(trace.output, "%s", bf);
3128 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003129 }
3130
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003131 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003132 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003133 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003134 fprintf(trace.output, "%s", bf);
3135 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003136 }
3137
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003138 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003139 trace.opts.target.system_wide = true;
3140
David Ahern6810fc92013-08-28 22:29:52 -06003141 if (input_name)
3142 err = trace__replay(&trace);
3143 else
3144 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003145
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003146out_close:
3147 if (output_name != NULL)
3148 fclose(trace.output);
3149out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003150 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003151}