blob: 4370ce4f28c7899447a3369ffd19acf4ac6b822c [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 Melo844ae5b2014-02-10 14:09:48 -0300341#if defined(__i386__) || defined(__x86_64__)
342/*
343 * FIXME: Make this available to all arches as soon as the ioctl beautifier
344 * gets rewritten to support all arches.
345 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300346static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
347 struct syscall_arg *arg)
348{
349 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
350}
351
352#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300353#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300354
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300355#ifndef AT_FDCWD
356#define AT_FDCWD -100
357#endif
358
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300359static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
360 struct syscall_arg *arg)
361{
362 int fd = arg->val;
363
364 if (fd == AT_FDCWD)
365 return scnprintf(bf, size, "CWD");
366
367 return syscall_arg__scnprintf_fd(bf, size, arg);
368}
369
370#define SCA_FDAT syscall_arg__scnprintf_fd_at
371
372static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
373 struct syscall_arg *arg);
374
375#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
376
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300377size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300378{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300379 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300380}
381
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300382size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300383{
384 return scnprintf(bf, size, "%d", arg->val);
385}
386
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300387size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
388{
389 return scnprintf(bf, size, "%ld", arg->val);
390}
391
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300392static const char *bpf_cmd[] = {
393 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
394 "MAP_GET_NEXT_KEY", "PROG_LOAD",
395};
396static DEFINE_STRARRAY(bpf_cmd);
397
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300398static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
399static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300400
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300401static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
402static DEFINE_STRARRAY(itimers);
403
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300404static const char *keyctl_options[] = {
405 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
406 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
407 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
408 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
409 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
410};
411static DEFINE_STRARRAY(keyctl_options);
412
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300413static const char *whences[] = { "SET", "CUR", "END",
414#ifdef SEEK_DATA
415"DATA",
416#endif
417#ifdef SEEK_HOLE
418"HOLE",
419#endif
420};
421static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300422
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300423static const char *fcntl_cmds[] = {
424 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300425 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
426 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
427 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300428};
429static DEFINE_STRARRAY(fcntl_cmds);
430
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300431static const char *fcntl_linux_specific_cmds[] = {
432 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
433 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300434 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300435};
436
437static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
438
439static struct strarray *fcntl_cmds_arrays[] = {
440 &strarray__fcntl_cmds,
441 &strarray__fcntl_linux_specific_cmds,
442};
443
444static DEFINE_STRARRAYS(fcntl_cmds_arrays);
445
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300446static const char *rlimit_resources[] = {
447 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
448 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
449 "RTTIME",
450};
451static DEFINE_STRARRAY(rlimit_resources);
452
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300453static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
454static DEFINE_STRARRAY(sighow);
455
David Ahern4f8c1b72013-09-22 19:45:00 -0600456static const char *clockid[] = {
457 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300458 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
459 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600460};
461static DEFINE_STRARRAY(clockid);
462
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300463static const char *socket_families[] = {
464 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
465 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
466 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
467 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
468 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
469 "ALG", "NFC", "VSOCK",
470};
471static DEFINE_STRARRAY(socket_families);
472
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300473static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
474 struct syscall_arg *arg)
475{
476 size_t printed = 0;
477 int mode = arg->val;
478
479 if (mode == F_OK) /* 0 */
480 return scnprintf(bf, size, "F");
481#define P_MODE(n) \
482 if (mode & n##_OK) { \
483 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
484 mode &= ~n##_OK; \
485 }
486
487 P_MODE(R);
488 P_MODE(W);
489 P_MODE(X);
490#undef P_MODE
491
492 if (mode)
493 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
494
495 return printed;
496}
497
498#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
499
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300500static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
501 struct syscall_arg *arg);
502
503#define SCA_FILENAME syscall_arg__scnprintf_filename
504
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300505static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
506 struct syscall_arg *arg)
507{
508 int printed = 0, flags = arg->val;
509
510#define P_FLAG(n) \
511 if (flags & O_##n) { \
512 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
513 flags &= ~O_##n; \
514 }
515
516 P_FLAG(CLOEXEC);
517 P_FLAG(NONBLOCK);
518#undef P_FLAG
519
520 if (flags)
521 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
522
523 return printed;
524}
525
526#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
527
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300528#if defined(__i386__) || defined(__x86_64__)
529/*
530 * FIXME: Make this available to all arches.
531 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300532#define TCGETS 0x5401
533
534static const char *tioctls[] = {
535 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
536 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
537 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
538 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
539 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
540 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
541 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
542 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
543 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
544 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
545 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
546 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
547 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
548 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
549 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
550};
551
552static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300553#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300554
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300555#ifndef GRND_NONBLOCK
556#define GRND_NONBLOCK 0x0001
557#endif
558#ifndef GRND_RANDOM
559#define GRND_RANDOM 0x0002
560#endif
561
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300562static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
563 struct syscall_arg *arg)
564{
565 int printed = 0, flags = arg->val;
566
567#define P_FLAG(n) \
568 if (flags & GRND_##n) { \
569 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
570 flags &= ~GRND_##n; \
571 }
572
573 P_FLAG(RANDOM);
574 P_FLAG(NONBLOCK);
575#undef P_FLAG
576
577 if (flags)
578 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
579
580 return printed;
581}
582
583#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
584
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300585#define STRARRAY(name, array) \
586 { .scnprintf = SCA_STRARRAY, \
587 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300588
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300589#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300590#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300591#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300592#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300593#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300594#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300595#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300596#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300597#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300598#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300599#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300600#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300601#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300602#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300603
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300604struct syscall_arg_fmt {
605 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
606 void *parm;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300607 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300608};
609
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300610static struct syscall_fmt {
611 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300612 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300613 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300614 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300615 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300616 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300617} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300618 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300619 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300620 { .name = "arch_prctl", .alias = "prctl", },
621 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300623 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300624 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300625 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300626 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300627 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300628 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300629 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300630 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300631 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300632 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300633 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300634 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300635 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300636 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300638 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300639 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300640 .parm = &strarrays__fcntl_cmds_arrays,
641 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300642 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300643 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300644 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300645 { .name = "fstat", .alias = "newfstat", },
646 { .name = "fstatat", .alias = "newfstatat", },
647 { .name = "futex",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300648 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300649 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300650 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300651 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300652 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300653 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300654 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300655 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300656 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300657 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300658 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300659 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300660 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300661 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300662#if defined(__i386__) || defined(__x86_64__)
663/*
664 * FIXME: Make this available to all arches.
665 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300666 [1] = { .scnprintf = SCA_STRHEXARRAY, /* cmd */
667 .parm = &strarray__tioctls, },
668 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300669#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300670 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300671#endif
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300672 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300673 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300676 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300677 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300678 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300679 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300680 { .name = "lstat", .alias = "newlstat", },
681 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
683 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300684 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300685 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300686 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300688 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300689 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300690 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300691 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300692 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200693/* The standard mmap maps to old_mmap on s390x */
694#if defined(__s390x__)
695 .alias = "old_mmap",
696#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300697 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
698 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
699 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300700 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300701 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
702 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300705 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300706 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
707 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
708 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300710 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300711 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300717 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300718 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300719 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300720 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
721 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300722 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300723 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
724 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300726 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
727 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
728 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300730 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300731 { .name = "poll", .timeout = true, },
732 { .name = "ppoll", .timeout = true, },
733 { .name = "pread", .alias = "pread64", },
734 { .name = "preadv", .alias = "pread", },
735 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300736 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300737 { .name = "pwrite", .alias = "pwrite64", },
738 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300745 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300746 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300747 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300748 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300749 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300750 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300756 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300757 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300758 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300759 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
760 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300761 { .name = "select", .timeout = true, },
762 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300764 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300765 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300766 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300768 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300769 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300770 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300771 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300772 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300773 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300774 .arg = { [0] = STRARRAY(family, socket_families),
775 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300776 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300777 .arg = { [0] = STRARRAY(family, socket_families),
778 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300779 { .name = "stat", .alias = "newstat", },
780 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300781 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
782 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
783 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300784 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300785 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300786 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300787 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300788 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300789 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300790 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300791 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300792 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300793 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300794 { .name = "uname", .alias = "newuname", },
795 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300796 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300797 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300798 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300799 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300800 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300801 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300802 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300803};
804
805static int syscall_fmt__cmp(const void *name, const void *fmtp)
806{
807 const struct syscall_fmt *fmt = fmtp;
808 return strcmp(name, fmt->name);
809}
810
811static struct syscall_fmt *syscall_fmt__find(const char *name)
812{
813 const int nmemb = ARRAY_SIZE(syscall_fmts);
814 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
815}
816
817struct syscall {
818 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300819 int nr_args;
820 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300821 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300822 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300823 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300824 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300825};
826
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300827/*
828 * We need to have this 'calculated' boolean because in some cases we really
829 * don't know what is the duration of a syscall, for instance, when we start
830 * a session and some threads are waiting for a syscall to finish, say 'poll',
831 * in which case all we can do is to print "( ? ) for duration and for the
832 * start timestamp.
833 */
834static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200835{
836 double duration = (double)t / NSEC_PER_MSEC;
837 size_t printed = fprintf(fp, "(");
838
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300839 if (!calculated)
840 printed += fprintf(fp, " ? ");
841 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200842 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
843 else if (duration >= 0.01)
844 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
845 else
846 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300847 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200848}
849
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300850/**
851 * filename.ptr: The filename char pointer that will be vfs_getname'd
852 * filename.entry_str_pos: Where to insert the string translated from
853 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300854 * ret_scnprintf: syscall args may set this to a different syscall return
855 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300856 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300857struct thread_trace {
858 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300859 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300860 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400861 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300862 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300863 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300864 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300865 struct {
866 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300867 short int entry_str_pos;
868 bool pending_open;
869 unsigned int namelen;
870 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300871 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300872 struct {
873 int max;
874 char **table;
875 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600876
877 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300878};
879
880static struct thread_trace *thread_trace__new(void)
881{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300882 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
883
884 if (ttrace)
885 ttrace->paths.max = -1;
886
David Ahernbf2575c2013-10-08 21:26:53 -0600887 ttrace->syscall_stats = intlist__new(NULL);
888
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300889 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890}
891
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300892static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300893{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300894 struct thread_trace *ttrace;
895
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300896 if (thread == NULL)
897 goto fail;
898
Namhyung Kim89dceb22014-10-06 09:46:03 +0900899 if (thread__priv(thread) == NULL)
900 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300901
Namhyung Kim89dceb22014-10-06 09:46:03 +0900902 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300903 goto fail;
904
Namhyung Kim89dceb22014-10-06 09:46:03 +0900905 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300906 ++ttrace->nr_events;
907
908 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300910 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300911 "WARNING: not enough memory, dropping samples!\n");
912 return NULL;
913}
914
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300915
916void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300917 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300918{
919 struct thread_trace *ttrace = thread__priv(arg->thread);
920
921 ttrace->ret_scnprintf = ret_scnprintf;
922}
923
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400924#define TRACE_PFMAJ (1 << 0)
925#define TRACE_PFMIN (1 << 1)
926
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300927static const size_t trace__entry_str_size = 2048;
928
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300929static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300930{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900931 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300932
933 if (fd > ttrace->paths.max) {
934 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
935
936 if (npath == NULL)
937 return -1;
938
939 if (ttrace->paths.max != -1) {
940 memset(npath + ttrace->paths.max + 1, 0,
941 (fd - ttrace->paths.max) * sizeof(char *));
942 } else {
943 memset(npath, 0, (fd + 1) * sizeof(char *));
944 }
945
946 ttrace->paths.table = npath;
947 ttrace->paths.max = fd;
948 }
949
950 ttrace->paths.table[fd] = strdup(pathname);
951
952 return ttrace->paths.table[fd] != NULL ? 0 : -1;
953}
954
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300955static int thread__read_fd_path(struct thread *thread, int fd)
956{
957 char linkname[PATH_MAX], pathname[PATH_MAX];
958 struct stat st;
959 int ret;
960
961 if (thread->pid_ == thread->tid) {
962 scnprintf(linkname, sizeof(linkname),
963 "/proc/%d/fd/%d", thread->pid_, fd);
964 } else {
965 scnprintf(linkname, sizeof(linkname),
966 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
967 }
968
969 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
970 return -1;
971
972 ret = readlink(linkname, pathname, sizeof(pathname));
973
974 if (ret < 0 || ret > st.st_size)
975 return -1;
976
977 pathname[ret] = '\0';
978 return trace__set_fd_pathname(thread, fd, pathname);
979}
980
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300981static const char *thread__fd_path(struct thread *thread, int fd,
982 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300983{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900984 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985
986 if (ttrace == NULL)
987 return NULL;
988
989 if (fd < 0)
990 return NULL;
991
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300992 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300993 if (!trace->live)
994 return NULL;
995 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300996 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300997 return NULL;
998 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300999
1000 return ttrace->paths.table[fd];
1001}
1002
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001003size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004{
1005 int fd = arg->val;
1006 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001007 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001008
1009 if (path)
1010 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1011
1012 return printed;
1013}
1014
1015static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1016 struct syscall_arg *arg)
1017{
1018 int fd = arg->val;
1019 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001020 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001022 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1023 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001024
1025 return printed;
1026}
1027
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001028static void thread__set_filename_pos(struct thread *thread, const char *bf,
1029 unsigned long ptr)
1030{
1031 struct thread_trace *ttrace = thread__priv(thread);
1032
1033 ttrace->filename.ptr = ptr;
1034 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1035}
1036
1037static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1038 struct syscall_arg *arg)
1039{
1040 unsigned long ptr = arg->val;
1041
1042 if (!arg->trace->vfs_getname)
1043 return scnprintf(bf, size, "%#x", ptr);
1044
1045 thread__set_filename_pos(arg->thread, bf, ptr);
1046 return 0;
1047}
1048
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001049static bool trace__filter_duration(struct trace *trace, double t)
1050{
1051 return t < (trace->duration_filter * NSEC_PER_MSEC);
1052}
1053
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001054static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001055{
1056 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1057
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001058 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001059}
1060
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001061/*
1062 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1063 * using ttrace->entry_time for a thread that receives a sys_exit without
1064 * first having received a sys_enter ("poll" issued before tracing session
1065 * starts, lost sys_enter exit due to ring buffer overflow).
1066 */
1067static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1068{
1069 if (tstamp > 0)
1070 return __trace__fprintf_tstamp(trace, tstamp, fp);
1071
1072 return fprintf(fp, " ? ");
1073}
1074
Namhyung Kimf15eb532012-10-05 14:02:16 +09001075static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001076static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001077
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001078static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001079{
1080 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001081 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001082}
1083
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001085 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086{
1087 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001088 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001089
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001090 if (trace->multiple_threads) {
1091 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001092 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001093 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001094 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001095
1096 return printed;
1097}
1098
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001099static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001100 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101{
1102 int ret = 0;
1103
1104 switch (event->header.type) {
1105 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001106 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001108 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001109 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001111 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001112 break;
1113 }
1114
1115 return ret;
1116}
1117
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001118static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001119 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001120 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121 struct machine *machine)
1122{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001123 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001124 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125}
1126
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001127static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1128{
1129 struct machine *machine = vmachine;
1130
1131 if (machine->kptr_restrict_warned)
1132 return NULL;
1133
1134 if (symbol_conf.kptr_restrict) {
1135 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1136 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1137 "Kernel samples will not be resolved.\n");
1138 machine->kptr_restrict_warned = true;
1139 return NULL;
1140 }
1141
1142 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1143}
1144
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1146{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001147 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148
1149 if (err)
1150 return err;
1151
David Ahern8fb598e2013-09-28 13:13:00 -06001152 trace->host = machine__new_host();
1153 if (trace->host == NULL)
1154 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001156 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001157 return -errno;
1158
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001159 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001160 evlist->threads, trace__tool_process, false,
1161 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001162 if (err)
1163 symbol__exit();
1164
1165 return err;
1166}
1167
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001168static int syscall__set_arg_fmts(struct syscall *sc)
1169{
1170 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001171 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001172
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001173 sc->arg_fmt = calloc(sc->nr_args, sizeof(*sc->arg_fmt));
1174 if (sc->arg_fmt == NULL)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001175 return -1;
1176
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001177 for (field = sc->args; field; field = field->next, ++idx) {
1178 if (sc->fmt) {
1179 sc->arg_fmt[idx] = sc->fmt->arg[idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001180
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001181 if (sc->fmt->arg[idx].scnprintf)
1182 continue;
1183 }
1184
1185 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001186 (strcmp(field->name, "filename") == 0 ||
1187 strcmp(field->name, "path") == 0 ||
1188 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001189 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001190 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001191 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001192 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001193 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001194 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001195 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001196 else if ((strcmp(field->type, "int") == 0 ||
1197 strcmp(field->type, "unsigned int") == 0 ||
1198 strcmp(field->type, "long") == 0) &&
1199 (len = strlen(field->name)) >= 2 &&
1200 strcmp(field->name + len - 2, "fd") == 0) {
1201 /*
1202 * /sys/kernel/tracing/events/syscalls/sys_enter*
1203 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1204 * 65 int
1205 * 23 unsigned int
1206 * 7 unsigned long
1207 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001208 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001209 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001210 }
1211
1212 return 0;
1213}
1214
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001215static int trace__read_syscall_info(struct trace *trace, int id)
1216{
1217 char tp_name[128];
1218 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001219 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001220
1221 if (name == NULL)
1222 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001223
1224 if (id > trace->syscalls.max) {
1225 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1226
1227 if (nsyscalls == NULL)
1228 return -1;
1229
1230 if (trace->syscalls.max != -1) {
1231 memset(nsyscalls + trace->syscalls.max + 1, 0,
1232 (id - trace->syscalls.max) * sizeof(*sc));
1233 } else {
1234 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1235 }
1236
1237 trace->syscalls.table = nsyscalls;
1238 trace->syscalls.max = id;
1239 }
1240
1241 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001242 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001243
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001244 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001245
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001246 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001247 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001248
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001249 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001250 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001251 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001252 }
1253
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001254 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001255 return -1;
1256
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001257 sc->args = sc->tp_format->format.fields;
1258 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001259 /*
1260 * We need to check and discard the first variable '__syscall_nr'
1261 * or 'nr' that mean the syscall number. It is needless here.
1262 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1263 */
1264 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001265 sc->args = sc->args->next;
1266 --sc->nr_args;
1267 }
1268
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001269 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1270
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001271 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001272}
1273
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001274static int trace__validate_ev_qualifier(struct trace *trace)
1275{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001276 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001277 struct str_node *pos;
1278
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001279 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1280 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1281 sizeof(trace->ev_qualifier_ids.entries[0]));
1282
1283 if (trace->ev_qualifier_ids.entries == NULL) {
1284 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1285 trace->output);
1286 err = -EINVAL;
1287 goto out;
1288 }
1289
1290 i = 0;
1291
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001292 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001293 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001294 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001295
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001296 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001297 if (err == 0) {
1298 fputs("Error:\tInvalid syscall ", trace->output);
1299 err = -EINVAL;
1300 } else {
1301 fputs(", ", trace->output);
1302 }
1303
1304 fputs(sc, trace->output);
1305 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001306
1307 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001308 }
1309
1310 if (err < 0) {
1311 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1312 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001313 zfree(&trace->ev_qualifier_ids.entries);
1314 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001315 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001316out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001317 return err;
1318}
1319
David Ahern55d43bca2015-02-19 15:00:22 -05001320/*
1321 * args is to be interpreted as a series of longs but we need to handle
1322 * 8-byte unaligned accesses. args points to raw_data within the event
1323 * and raw_data is guaranteed to be 8-byte unaligned because it is
1324 * preceded by raw_size which is a u32. So we need to copy args to a temp
1325 * variable to read it. Most notably this avoids extended load instructions
1326 * on unaligned addresses
1327 */
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001328static unsigned long __syscall_arg__val(unsigned char *args, u8 idx)
1329{
1330 unsigned long val;
1331 unsigned char *p = args + sizeof(unsigned long) * idx;
1332
1333 memcpy(&val, p, sizeof(val));
1334 return val;
1335}
1336
1337unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
1338{
1339 return __syscall_arg__val(arg->args, idx);
1340}
David Ahern55d43bca2015-02-19 15:00:22 -05001341
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001342static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001343 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001344 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001345{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001346 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001347 unsigned long val;
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001348 struct thread_trace *ttrace = thread__priv(thread);
1349
1350 /*
1351 * Things like fcntl will set this in its 'cmd' formatter to pick the
1352 * right formatter for the return value (an fd? file flags?), which is
1353 * not needed for syscalls that always return a given type, say an fd.
1354 */
1355 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001356
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001357 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001358 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001359 u8 bit = 1;
1360 struct syscall_arg arg = {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001361 .args = args,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001362 .idx = 0,
1363 .mask = 0,
1364 .trace = trace,
1365 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001366 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001367
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001368 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001369 field = field->next, ++arg.idx, bit <<= 1) {
1370 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001371 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001372
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001373 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001374
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001375 /*
1376 * Suppress this argument if its value is zero and
1377 * and we don't have a string associated in an
1378 * strarray for it.
1379 */
David Ahern55d43bca2015-02-19 15:00:22 -05001380 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001381 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001382 (sc->arg_fmt[arg.idx].show_zero ||
1383 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001384 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1385 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001386 continue;
1387
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001388 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001389 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001390 if (sc->arg_fmt && sc->arg_fmt[arg.idx].scnprintf) {
David Ahern55d43bca2015-02-19 15:00:22 -05001391 arg.val = val;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001392 if (sc->arg_fmt[arg.idx].parm)
1393 arg.parm = sc->arg_fmt[arg.idx].parm;
1394 printed += sc->arg_fmt[arg.idx].scnprintf(bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001395 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001396 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001397 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001398 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001399 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001400 } else if (IS_ERR(sc->tp_format)) {
1401 /*
1402 * If we managed to read the tracepoint /format file, then we
1403 * may end up not having any args, like with gettid(), so only
1404 * print the raw args when we didn't manage to read it.
1405 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001406 int i = 0;
1407
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001408 while (i < 6) {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001409 val = __syscall_arg__val(args, i);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001410 printed += scnprintf(bf + printed, size - printed,
1411 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001412 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001413 ++i;
1414 }
1415 }
1416
1417 return printed;
1418}
1419
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001420typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001421 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001422 struct perf_sample *sample);
1423
1424static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001425 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001426{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001427
1428 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001429
1430 /*
1431 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1432 * before that, leaving at a higher verbosity level till that is
1433 * explained. Reproduced with plain ftrace with:
1434 *
1435 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1436 * grep "NR -1 " /t/trace_pipe
1437 *
1438 * After generating some load on the machine.
1439 */
1440 if (verbose > 1) {
1441 static u64 n;
1442 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1443 id, perf_evsel__name(evsel), ++n);
1444 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001445 return NULL;
1446 }
1447
1448 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1449 trace__read_syscall_info(trace, id))
1450 goto out_cant_read;
1451
1452 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1453 goto out_cant_read;
1454
1455 return &trace->syscalls.table[id];
1456
1457out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001458 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001459 fprintf(trace->output, "Problems reading syscall %d", id);
1460 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1461 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1462 fputs(" information\n", trace->output);
1463 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001464 return NULL;
1465}
1466
David Ahernbf2575c2013-10-08 21:26:53 -06001467static void thread__update_stats(struct thread_trace *ttrace,
1468 int id, struct perf_sample *sample)
1469{
1470 struct int_node *inode;
1471 struct stats *stats;
1472 u64 duration = 0;
1473
1474 inode = intlist__findnew(ttrace->syscall_stats, id);
1475 if (inode == NULL)
1476 return;
1477
1478 stats = inode->priv;
1479 if (stats == NULL) {
1480 stats = malloc(sizeof(struct stats));
1481 if (stats == NULL)
1482 return;
1483 init_stats(stats);
1484 inode->priv = stats;
1485 }
1486
1487 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1488 duration = sample->time - ttrace->entry_time;
1489
1490 update_stats(stats, duration);
1491}
1492
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001493static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1494{
1495 struct thread_trace *ttrace;
1496 u64 duration;
1497 size_t printed;
1498
1499 if (trace->current == NULL)
1500 return 0;
1501
1502 ttrace = thread__priv(trace->current);
1503
1504 if (!ttrace->entry_pending)
1505 return 0;
1506
1507 duration = sample->time - ttrace->entry_time;
1508
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001509 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001510 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1511 ttrace->entry_pending = false;
1512
1513 return printed;
1514}
1515
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001516static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001517 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001518 struct perf_sample *sample)
1519{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001521 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001522 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001523 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001524 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001525 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001526 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001527
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001528 if (sc == NULL)
1529 return -1;
1530
David Ahern8fb598e2013-09-28 13:13:00 -06001531 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001532 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001533 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001534 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001535
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001536 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001537
1538 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001539 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001540 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001541 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001542 }
1543
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001544 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001545 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001546
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001547 ttrace->entry_time = sample->time;
1548 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001549 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001550
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001551 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001552 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001553
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001554 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001555 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001556 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001557 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001558 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001559 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001560 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001561 /* See trace__vfs_getname & trace__sys_exit */
1562 ttrace->filename.pending_open = false;
1563 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001564
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001565 if (trace->current != thread) {
1566 thread__put(trace->current);
1567 trace->current = thread__get(thread);
1568 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001569 err = 0;
1570out_put:
1571 thread__put(thread);
1572 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001573}
1574
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001575static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1576 struct perf_sample *sample,
1577 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001578{
1579 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001580
1581 if (machine__resolve(trace->host, &al, sample) < 0 ||
1582 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1583 return -1;
1584
1585 return 0;
1586}
1587
1588static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1589{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001590 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001591 const unsigned int print_opts = EVSEL__PRINT_SYM |
1592 EVSEL__PRINT_DSO |
1593 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001594
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001595 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001596}
1597
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001598static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001599 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001600 struct perf_sample *sample)
1601{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001602 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001603 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001604 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001605 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001606 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001607 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001608 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001609
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001610 if (sc == NULL)
1611 return -1;
1612
David Ahern8fb598e2013-09-28 13:13:00 -06001613 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001614 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001615 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001616 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001617
David Ahernbf2575c2013-10-08 21:26:53 -06001618 if (trace->summary)
1619 thread__update_stats(ttrace, id, sample);
1620
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001621 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001622
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001623 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001624 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1625 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001626 ++trace->stats.vfs_getname;
1627 }
1628
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001629 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001630 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001631 if (trace__filter_duration(trace, duration))
1632 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001633 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001634 } else if (trace->duration_filter)
1635 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001636
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001637 if (sample->callchain) {
1638 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1639 if (callchain_ret == 0) {
1640 if (callchain_cursor.nr < trace->min_stack)
1641 goto out;
1642 callchain_ret = 1;
1643 }
1644 }
1645
David Ahernfd2eaba2013-11-12 09:31:15 -07001646 if (trace->summary_only)
1647 goto out;
1648
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001649 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001650
1651 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001652 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001653 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001654 fprintf(trace->output, " ... [");
1655 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1656 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001657 }
1658
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001659 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001660 if (ret < 0)
1661 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001662signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001663 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001664 } else if (ret < 0) {
1665errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001666 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001667 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001668 *e = audit_errno_to_name(-ret);
1669
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001670 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001671 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001672 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001673 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001674 else if (ttrace->ret_scnprintf) {
1675 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001676 struct syscall_arg arg = {
1677 .val = ret,
1678 .thread = thread,
1679 .trace = trace,
1680 };
1681 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001682 ttrace->ret_scnprintf = NULL;
1683 fprintf(trace->output, ") = %s", bf);
1684 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001685 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001686 else if (sc->fmt->errpid) {
1687 struct thread *child = machine__find_thread(trace->host, ret, ret);
1688
1689 if (child != NULL) {
1690 fprintf(trace->output, ") = %ld", ret);
1691 if (child->comm_set)
1692 fprintf(trace->output, " (%s)", thread__comm_str(child));
1693 thread__put(child);
1694 }
1695 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001696 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001697
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001698 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001699
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001700 if (callchain_ret > 0)
1701 trace__fprintf_callchain(trace, sample);
1702 else if (callchain_ret < 0)
1703 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001704out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001705 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001706 err = 0;
1707out_put:
1708 thread__put(thread);
1709 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001710}
1711
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001712static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001713 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001714 struct perf_sample *sample)
1715{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001716 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1717 struct thread_trace *ttrace;
1718 size_t filename_len, entry_str_len, to_move;
1719 ssize_t remaining_space;
1720 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001721 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001722
1723 if (!thread)
1724 goto out;
1725
1726 ttrace = thread__priv(thread);
1727 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001728 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001729
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001730 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001731 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001732 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001733
1734 if (ttrace->filename.namelen < filename_len) {
1735 char *f = realloc(ttrace->filename.name, filename_len + 1);
1736
1737 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001738 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001739
1740 ttrace->filename.namelen = filename_len;
1741 ttrace->filename.name = f;
1742 }
1743
1744 strcpy(ttrace->filename.name, filename);
1745 ttrace->filename.pending_open = true;
1746
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001747 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001748 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001749
1750 entry_str_len = strlen(ttrace->entry_str);
1751 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1752 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001753 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001754
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001755 if (filename_len > (size_t)remaining_space) {
1756 filename += filename_len - remaining_space;
1757 filename_len = remaining_space;
1758 }
1759
1760 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1761 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1762 memmove(pos + filename_len, pos, to_move);
1763 memcpy(pos, filename, filename_len);
1764
1765 ttrace->filename.ptr = 0;
1766 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001767out_put:
1768 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001769out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001770 return 0;
1771}
1772
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001773static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001774 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001775 struct perf_sample *sample)
1776{
1777 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1778 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001779 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001780 sample->pid,
1781 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001782 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001783
1784 if (ttrace == NULL)
1785 goto out_dump;
1786
1787 ttrace->runtime_ms += runtime_ms;
1788 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001789out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001790 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001791 return 0;
1792
1793out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001794 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001795 evsel->name,
1796 perf_evsel__strval(evsel, sample, "comm"),
1797 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1798 runtime,
1799 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001800 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001801}
1802
Wang Nan1d6c9402016-02-26 09:31:55 +00001803static void bpf_output__printer(enum binary_printer_ops op,
1804 unsigned int val, void *extra)
1805{
1806 FILE *output = extra;
1807 unsigned char ch = (unsigned char)val;
1808
1809 switch (op) {
1810 case BINARY_PRINT_CHAR_DATA:
1811 fprintf(output, "%c", isprint(ch) ? ch : '.');
1812 break;
1813 case BINARY_PRINT_DATA_BEGIN:
1814 case BINARY_PRINT_LINE_BEGIN:
1815 case BINARY_PRINT_ADDR:
1816 case BINARY_PRINT_NUM_DATA:
1817 case BINARY_PRINT_NUM_PAD:
1818 case BINARY_PRINT_SEP:
1819 case BINARY_PRINT_CHAR_PAD:
1820 case BINARY_PRINT_LINE_END:
1821 case BINARY_PRINT_DATA_END:
1822 default:
1823 break;
1824 }
1825}
1826
1827static void bpf_output__fprintf(struct trace *trace,
1828 struct perf_sample *sample)
1829{
1830 print_binary(sample->raw_data, sample->raw_size, 8,
1831 bpf_output__printer, trace->output);
1832}
1833
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001834static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1835 union perf_event *event __maybe_unused,
1836 struct perf_sample *sample)
1837{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001838 int callchain_ret = 0;
1839
1840 if (sample->callchain) {
1841 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1842 if (callchain_ret == 0) {
1843 if (callchain_cursor.nr < trace->min_stack)
1844 goto out;
1845 callchain_ret = 1;
1846 }
1847 }
1848
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001849 trace__printf_interrupted_entry(trace, sample);
1850 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001851
1852 if (trace->trace_syscalls)
1853 fprintf(trace->output, "( ): ");
1854
1855 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001856
Wang Nan1d6c9402016-02-26 09:31:55 +00001857 if (perf_evsel__is_bpf_output(evsel)) {
1858 bpf_output__fprintf(trace, sample);
1859 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001860 event_format__fprintf(evsel->tp_format, sample->cpu,
1861 sample->raw_data, sample->raw_size,
1862 trace->output);
1863 }
1864
1865 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001866
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001867 if (callchain_ret > 0)
1868 trace__fprintf_callchain(trace, sample);
1869 else if (callchain_ret < 0)
1870 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1871out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001872 return 0;
1873}
1874
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001875static void print_location(FILE *f, struct perf_sample *sample,
1876 struct addr_location *al,
1877 bool print_dso, bool print_sym)
1878{
1879
Namhyung Kimbb963e12017-02-17 17:17:38 +09001880 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001881 fprintf(f, "%s@", al->map->dso->long_name);
1882
Namhyung Kimbb963e12017-02-17 17:17:38 +09001883 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001884 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001885 al->addr - al->sym->start);
1886 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001887 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001889 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001890}
1891
1892static int trace__pgfault(struct trace *trace,
1893 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001894 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001895 struct perf_sample *sample)
1896{
1897 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001898 struct addr_location al;
1899 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001900 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001901 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001902 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001903
1904 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001905
1906 if (sample->callchain) {
1907 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1908 if (callchain_ret == 0) {
1909 if (callchain_cursor.nr < trace->min_stack)
1910 goto out_put;
1911 callchain_ret = 1;
1912 }
1913 }
1914
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001915 ttrace = thread__trace(thread, trace->output);
1916 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001917 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001918
1919 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1920 ttrace->pfmaj++;
1921 else
1922 ttrace->pfmin++;
1923
1924 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001925 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001926
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001927 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001928 sample->ip, &al);
1929
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001930 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001931
1932 fprintf(trace->output, "%sfault [",
1933 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1934 "maj" : "min");
1935
1936 print_location(trace->output, sample, &al, false, true);
1937
1938 fprintf(trace->output, "] => ");
1939
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001940 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001941 sample->addr, &al);
1942
1943 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001944 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001945 MAP__FUNCTION, sample->addr, &al);
1946
1947 if (al.map)
1948 map_type = 'x';
1949 else
1950 map_type = '?';
1951 }
1952
1953 print_location(trace->output, sample, &al, true, false);
1954
1955 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001956
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001957 if (callchain_ret > 0)
1958 trace__fprintf_callchain(trace, sample);
1959 else if (callchain_ret < 0)
1960 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001961out:
1962 err = 0;
1963out_put:
1964 thread__put(thread);
1965 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001966}
1967
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001968static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001969 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001970 struct perf_sample *sample)
1971{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001972 /*
1973 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1974 * and don't use sample->time unconditionally, we may end up having
1975 * some other event in the future without PERF_SAMPLE_TIME for good
1976 * reason, i.e. we may not be interested in its timestamps, just in
1977 * it taking place, picking some piece of information when it
1978 * appears in our event stream (vfs_getname comes to mind).
1979 */
1980 if (trace->base_time == 0 && !trace->full_time &&
1981 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001982 trace->base_time = sample->time;
1983}
1984
David Ahern6810fc92013-08-28 22:29:52 -06001985static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001986 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001987 struct perf_sample *sample,
1988 struct perf_evsel *evsel,
1989 struct machine *machine __maybe_unused)
1990{
1991 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07001992 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06001993 int err = 0;
1994
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03001995 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06001996
David Ahernaa07df62016-11-25 09:29:52 -07001997 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1998 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001999 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002000
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002001 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002002
David Ahern31605652013-12-04 19:41:41 -07002003 if (handler) {
2004 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002005 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002006 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002007out:
2008 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002009 return err;
2010}
2011
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002012static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002013{
2014 unsigned int rec_argc, i, j;
2015 const char **rec_argv;
2016 const char * const record_args[] = {
2017 "record",
2018 "-R",
2019 "-m", "1024",
2020 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002021 };
2022
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002023 const char * const sc_args[] = { "-e", };
2024 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2025 const char * const majpf_args[] = { "-e", "major-faults" };
2026 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2027 const char * const minpf_args[] = { "-e", "minor-faults" };
2028 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2029
David Ahern9aca7f12013-12-04 19:41:39 -07002030 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002031 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2032 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002033 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2034
2035 if (rec_argv == NULL)
2036 return -ENOMEM;
2037
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002038 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002039 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002040 rec_argv[j++] = record_args[i];
2041
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002042 if (trace->trace_syscalls) {
2043 for (i = 0; i < sc_args_nr; i++)
2044 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002045
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002046 /* event string may be different for older kernels - e.g., RHEL6 */
2047 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2048 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2049 else if (is_valid_tracepoint("syscalls:sys_enter"))
2050 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2051 else {
2052 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2053 return -1;
2054 }
David Ahern9aca7f12013-12-04 19:41:39 -07002055 }
David Ahern9aca7f12013-12-04 19:41:39 -07002056
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002057 if (trace->trace_pgfaults & TRACE_PFMAJ)
2058 for (i = 0; i < majpf_args_nr; i++)
2059 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002060
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002061 if (trace->trace_pgfaults & TRACE_PFMIN)
2062 for (i = 0; i < minpf_args_nr; i++)
2063 rec_argv[j++] = minpf_args[i];
2064
2065 for (i = 0; i < (unsigned int)argc; i++)
2066 rec_argv[j++] = argv[i];
2067
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002068 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002069}
2070
David Ahernbf2575c2013-10-08 21:26:53 -06002071static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2072
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002073static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002074{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002075 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002076
2077 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002078 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002079
2080 if (perf_evsel__field(evsel, "pathname") == NULL) {
2081 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002082 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002083 }
2084
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002085 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002086 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002087 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002088}
2089
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002090static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002091{
2092 struct perf_evsel *evsel;
2093 struct perf_event_attr attr = {
2094 .type = PERF_TYPE_SOFTWARE,
2095 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002096 };
2097
2098 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002099 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002100
2101 event_attr_init(&attr);
2102
2103 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002104 if (evsel)
2105 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002106
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002107 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002108}
2109
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002110static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2111{
2112 const u32 type = event->header.type;
2113 struct perf_evsel *evsel;
2114
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002115 if (type != PERF_RECORD_SAMPLE) {
2116 trace__process_event(trace, trace->host, event, sample);
2117 return;
2118 }
2119
2120 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2121 if (evsel == NULL) {
2122 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2123 return;
2124 }
2125
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002126 trace__set_base_time(trace, evsel, sample);
2127
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002128 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2129 sample->raw_data == NULL) {
2130 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2131 perf_evsel__name(evsel), sample->tid,
2132 sample->cpu, sample->raw_size);
2133 } else {
2134 tracepoint_handler handler = evsel->handler;
2135 handler(trace, evsel, event, sample);
2136 }
2137}
2138
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002139static int trace__add_syscall_newtp(struct trace *trace)
2140{
2141 int ret = -1;
2142 struct perf_evlist *evlist = trace->evlist;
2143 struct perf_evsel *sys_enter, *sys_exit;
2144
2145 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2146 if (sys_enter == NULL)
2147 goto out;
2148
2149 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2150 goto out_delete_sys_enter;
2151
2152 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2153 if (sys_exit == NULL)
2154 goto out_delete_sys_enter;
2155
2156 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2157 goto out_delete_sys_exit;
2158
2159 perf_evlist__add(evlist, sys_enter);
2160 perf_evlist__add(evlist, sys_exit);
2161
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002162 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002163 /*
2164 * We're interested only in the user space callchain
2165 * leading to the syscall, allow overriding that for
2166 * debugging reasons using --kernel_syscall_callchains
2167 */
2168 sys_exit->attr.exclude_callchain_kernel = 1;
2169 }
2170
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002171 trace->syscalls.events.sys_enter = sys_enter;
2172 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002173
2174 ret = 0;
2175out:
2176 return ret;
2177
2178out_delete_sys_exit:
2179 perf_evsel__delete_priv(sys_exit);
2180out_delete_sys_enter:
2181 perf_evsel__delete_priv(sys_enter);
2182 goto out;
2183}
2184
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002185static int trace__set_ev_qualifier_filter(struct trace *trace)
2186{
2187 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002188 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002189 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2190 trace->ev_qualifier_ids.nr,
2191 trace->ev_qualifier_ids.entries);
2192
2193 if (filter == NULL)
2194 goto out_enomem;
2195
Mathieu Poirier3541c032016-09-16 08:44:04 -06002196 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2197 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002198 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002199 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002200 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002201
2202 free(filter);
2203out:
2204 return err;
2205out_enomem:
2206 errno = ENOMEM;
2207 goto out;
2208}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002209
Namhyung Kimf15eb532012-10-05 14:02:16 +09002210static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002211{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002212 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002213 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002214 int err = -1, i;
2215 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002216 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002217 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002218
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002219 trace->live = true;
2220
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002221 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002222 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002223
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002224 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002225 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002226
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002227 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2228 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2229 if (pgfault_maj == NULL)
2230 goto out_error_mem;
2231 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002232 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002233
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002234 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2235 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2236 if (pgfault_min == NULL)
2237 goto out_error_mem;
2238 perf_evlist__add(evlist, pgfault_min);
2239 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002240
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002241 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002242 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2243 trace__sched_stat_runtime))
2244 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002245
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002246 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2247 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002248 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002249 goto out_delete_evlist;
2250 }
2251
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002252 err = trace__symbols_init(trace, evlist);
2253 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002254 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002255 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002256 }
2257
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002258 perf_evlist__config(evlist, &trace->opts, NULL);
2259
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002260 if (callchain_param.enabled) {
2261 bool use_identifier = false;
2262
2263 if (trace->syscalls.events.sys_exit) {
2264 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2265 &trace->opts, &callchain_param);
2266 use_identifier = true;
2267 }
2268
2269 if (pgfault_maj) {
2270 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2271 use_identifier = true;
2272 }
2273
2274 if (pgfault_min) {
2275 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2276 use_identifier = true;
2277 }
2278
2279 if (use_identifier) {
2280 /*
2281 * Now we have evsels with different sample_ids, use
2282 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2283 * from a fixed position in each ring buffer record.
2284 *
2285 * As of this the changeset introducing this comment, this
2286 * isn't strictly needed, as the fields that can come before
2287 * PERF_SAMPLE_ID are all used, but we'll probably disable
2288 * some of those for things like copying the payload of
2289 * pointer syscall arguments, and for vfs_getname we don't
2290 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2291 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2292 */
2293 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2294 perf_evlist__reset_sample_bit(evlist, ID);
2295 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002296 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002297
Namhyung Kimf15eb532012-10-05 14:02:16 +09002298 signal(SIGCHLD, sig_handler);
2299 signal(SIGINT, sig_handler);
2300
2301 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002302 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002303 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002304 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002305 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002306 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002307 }
2308 }
2309
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002310 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002311 if (err < 0)
2312 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002313
Wang Nanba504232016-02-26 09:31:54 +00002314 err = bpf__apply_obj_config();
2315 if (err) {
2316 char errbuf[BUFSIZ];
2317
2318 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2319 pr_err("ERROR: Apply config to BPF failed: %s\n",
2320 errbuf);
2321 goto out_error_open;
2322 }
2323
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002324 /*
2325 * Better not use !target__has_task() here because we need to cover the
2326 * case where no threads were specified in the command line, but a
2327 * workload was, and in that case we will fill in the thread_map when
2328 * we fork the workload in perf_evlist__prepare_workload.
2329 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002330 if (trace->filter_pids.nr > 0)
2331 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002332 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002333 err = perf_evlist__set_filter_pid(evlist, getpid());
2334
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002335 if (err < 0)
2336 goto out_error_mem;
2337
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002338 if (trace->ev_qualifier_ids.nr > 0) {
2339 err = trace__set_ev_qualifier_filter(trace);
2340 if (err < 0)
2341 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002342
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002343 pr_debug("event qualifier tracepoint filter: %s\n",
2344 trace->syscalls.events.sys_exit->filter);
2345 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002346
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002347 err = perf_evlist__apply_filters(evlist, &evsel);
2348 if (err < 0)
2349 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002350
Jiri Olsaf8850372013-11-28 17:57:22 +01002351 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002352 if (err < 0)
2353 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002354
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002355 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002356 perf_evlist__enable(evlist);
2357
Namhyung Kimf15eb532012-10-05 14:02:16 +09002358 if (forks)
2359 perf_evlist__start_workload(evlist);
2360
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002361 if (trace->opts.initial_delay) {
2362 usleep(trace->opts.initial_delay * 1000);
2363 perf_evlist__enable(evlist);
2364 }
2365
Jiri Olsae13798c2015-06-23 00:36:02 +02002366 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002367 evlist->threads->nr > 1 ||
2368 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002369again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002370 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002371
2372 for (i = 0; i < evlist->nr_mmaps; i++) {
2373 union perf_event *event;
2374
2375 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002376 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002377
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002378 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002379
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002380 err = perf_evlist__parse_sample(evlist, event, &sample);
2381 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002382 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002383 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002384 }
2385
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002386 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002387next_event:
2388 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002389
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002390 if (interrupted)
2391 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002392
2393 if (done && !draining) {
2394 perf_evlist__disable(evlist);
2395 draining = true;
2396 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002397 }
2398 }
2399
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002400 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002401 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002402
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002403 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2404 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2405 draining = true;
2406
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002407 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002408 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002409 } else {
2410 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002411 }
2412
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002413out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002414 thread__zput(trace->current);
2415
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002416 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002417
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002418 if (!err) {
2419 if (trace->summary)
2420 trace__fprintf_thread_summary(trace, trace->output);
2421
2422 if (trace->show_tool_stats) {
2423 fprintf(trace->output, "Stats:\n "
2424 " vfs_getname : %" PRIu64 "\n"
2425 " proc_getname: %" PRIu64 "\n",
2426 trace->stats.vfs_getname,
2427 trace->stats.proc_getname);
2428 }
2429 }
David Ahernbf2575c2013-10-08 21:26:53 -06002430
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002431out_delete_evlist:
2432 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002433 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002434 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002435 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002436{
2437 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002438
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002439out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002440 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002441 goto out_error;
2442
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002443out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002444 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002445 goto out_error;
2446
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002447out_error_mmap:
2448 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2449 goto out_error;
2450
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002451out_error_open:
2452 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2453
2454out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002455 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302456 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002457
2458out_error_apply_filters:
2459 fprintf(trace->output,
2460 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2461 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002462 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002463 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002464}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002465out_error_mem:
2466 fprintf(trace->output, "Not enough memory to run!\n");
2467 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002468
2469out_errno:
2470 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2471 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002472}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002473
David Ahern6810fc92013-08-28 22:29:52 -06002474static int trace__replay(struct trace *trace)
2475{
2476 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002477 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002478 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002479 struct perf_data_file file = {
2480 .path = input_name,
2481 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002482 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002483 };
David Ahern6810fc92013-08-28 22:29:52 -06002484 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002485 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002486 int err = -1;
2487
2488 trace->tool.sample = trace__process_sample;
2489 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002490 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002491 trace->tool.comm = perf_event__process_comm;
2492 trace->tool.exit = perf_event__process_exit;
2493 trace->tool.fork = perf_event__process_fork;
2494 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302495 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002496 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302497 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002498
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002499 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002500 trace->tool.ordering_requires_timestamps = true;
2501
2502 /* add tid to output */
2503 trace->multiple_threads = true;
2504
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002505 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002506 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002507 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002508
David Ahernaa07df62016-11-25 09:29:52 -07002509 if (trace->opts.target.pid)
2510 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2511
2512 if (trace->opts.target.tid)
2513 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2514
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002515 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002516 goto out;
2517
David Ahern8fb598e2013-09-28 13:13:00 -06002518 trace->host = &session->machines.host;
2519
David Ahern6810fc92013-08-28 22:29:52 -06002520 err = perf_session__set_tracepoints_handlers(session, handlers);
2521 if (err)
2522 goto out;
2523
Namhyung Kim003824e2013-11-12 15:25:00 +09002524 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2525 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002526 /* older kernels have syscalls tp versus raw_syscalls */
2527 if (evsel == NULL)
2528 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2529 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002530
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002531 if (evsel &&
2532 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2533 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002534 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2535 goto out;
2536 }
2537
2538 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2539 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002540 if (evsel == NULL)
2541 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2542 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002543 if (evsel &&
2544 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2545 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002546 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002547 goto out;
2548 }
2549
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002550 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002551 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2552 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2553 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2554 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2555 evsel->handler = trace__pgfault;
2556 }
2557
David Ahern6810fc92013-08-28 22:29:52 -06002558 setup_pager();
2559
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002560 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002561 if (err)
2562 pr_err("Failed to process events, error %d", err);
2563
David Ahernbf2575c2013-10-08 21:26:53 -06002564 else if (trace->summary)
2565 trace__fprintf_thread_summary(trace, trace->output);
2566
David Ahern6810fc92013-08-28 22:29:52 -06002567out:
2568 perf_session__delete(session);
2569
2570 return err;
2571}
2572
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002573static size_t trace__fprintf_threads_header(FILE *fp)
2574{
2575 size_t printed;
2576
Pekka Enberg99ff7152013-11-12 16:42:14 +02002577 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002578
2579 return printed;
2580}
2581
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002582DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2583 struct stats *stats;
2584 double msecs;
2585 int syscall;
2586)
2587{
2588 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2589 struct stats *stats = source->priv;
2590
2591 entry->syscall = source->i;
2592 entry->stats = stats;
2593 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2594}
2595
David Ahernbf2575c2013-10-08 21:26:53 -06002596static size_t thread__dump_stats(struct thread_trace *ttrace,
2597 struct trace *trace, FILE *fp)
2598{
David Ahernbf2575c2013-10-08 21:26:53 -06002599 size_t printed = 0;
2600 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002601 struct rb_node *nd;
2602 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002603
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002604 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002605 return 0;
2606
2607 printed += fprintf(fp, "\n");
2608
Milian Wolff834fd462015-08-06 11:24:29 +02002609 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2610 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2611 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002612
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002613 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002614 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002615 if (stats) {
2616 double min = (double)(stats->min) / NSEC_PER_MSEC;
2617 double max = (double)(stats->max) / NSEC_PER_MSEC;
2618 double avg = avg_stats(stats);
2619 double pct;
2620 u64 n = (u64) stats->n;
2621
2622 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2623 avg /= NSEC_PER_MSEC;
2624
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002625 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002626 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002627 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002628 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002629 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002630 }
David Ahernbf2575c2013-10-08 21:26:53 -06002631 }
2632
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002633 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002634 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002635
2636 return printed;
2637}
2638
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002639static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002640{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002641 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002642 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002643 double ratio;
2644
2645 if (ttrace == NULL)
2646 return 0;
2647
2648 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2649
Pekka Enberg15e65c62013-11-14 18:43:30 +02002650 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002651 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002652 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002653 if (ttrace->pfmaj)
2654 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2655 if (ttrace->pfmin)
2656 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002657 if (trace->sched)
2658 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2659 else if (fputc('\n', fp) != EOF)
2660 ++printed;
2661
David Ahernbf2575c2013-10-08 21:26:53 -06002662 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002663
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002664 return printed;
2665}
David Ahern896cbb52013-09-28 13:12:59 -06002666
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002667static unsigned long thread__nr_events(struct thread_trace *ttrace)
2668{
2669 return ttrace ? ttrace->nr_events : 0;
2670}
2671
2672DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2673 struct thread *thread;
2674)
2675{
2676 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002677}
2678
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002679static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2680{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002681 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2682 size_t printed = trace__fprintf_threads_header(fp);
2683 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002684
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002685 if (threads == NULL) {
2686 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2687 return 0;
2688 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002689
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002690 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002691 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2692
2693 resort_rb__delete(threads);
2694
2695 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002696}
2697
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002698static int trace__set_duration(const struct option *opt, const char *str,
2699 int unset __maybe_unused)
2700{
2701 struct trace *trace = opt->value;
2702
2703 trace->duration_filter = atof(str);
2704 return 0;
2705}
2706
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002707static int trace__set_filter_pids(const struct option *opt, const char *str,
2708 int unset __maybe_unused)
2709{
2710 int ret = -1;
2711 size_t i;
2712 struct trace *trace = opt->value;
2713 /*
2714 * FIXME: introduce a intarray class, plain parse csv and create a
2715 * { int nr, int entries[] } struct...
2716 */
2717 struct intlist *list = intlist__new(str);
2718
2719 if (list == NULL)
2720 return -1;
2721
2722 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2723 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2724
2725 if (trace->filter_pids.entries == NULL)
2726 goto out;
2727
2728 trace->filter_pids.entries[0] = getpid();
2729
2730 for (i = 1; i < trace->filter_pids.nr; ++i)
2731 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2732
2733 intlist__delete(list);
2734 ret = 0;
2735out:
2736 return ret;
2737}
2738
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002739static int trace__open_output(struct trace *trace, const char *filename)
2740{
2741 struct stat st;
2742
2743 if (!stat(filename, &st) && st.st_size) {
2744 char oldname[PATH_MAX];
2745
2746 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2747 unlink(oldname);
2748 rename(filename, oldname);
2749 }
2750
2751 trace->output = fopen(filename, "w");
2752
2753 return trace->output == NULL ? -errno : 0;
2754}
2755
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002756static int parse_pagefaults(const struct option *opt, const char *str,
2757 int unset __maybe_unused)
2758{
2759 int *trace_pgfaults = opt->value;
2760
2761 if (strcmp(str, "all") == 0)
2762 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2763 else if (strcmp(str, "maj") == 0)
2764 *trace_pgfaults |= TRACE_PFMAJ;
2765 else if (strcmp(str, "min") == 0)
2766 *trace_pgfaults |= TRACE_PFMIN;
2767 else
2768 return -1;
2769
2770 return 0;
2771}
2772
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002773static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2774{
2775 struct perf_evsel *evsel;
2776
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002777 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002778 evsel->handler = handler;
2779}
2780
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002781/*
2782 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2783 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2784 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2785 *
2786 * It'd be better to introduce a parse_options() variant that would return a
2787 * list with the terms it didn't match to an event...
2788 */
2789static int trace__parse_events_option(const struct option *opt, const char *str,
2790 int unset __maybe_unused)
2791{
2792 struct trace *trace = (struct trace *)opt->value;
2793 const char *s = str;
2794 char *sep = NULL, *lists[2] = { NULL, NULL, };
2795 int len = strlen(str), err = -1, list;
2796 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2797 char group_name[PATH_MAX];
2798
2799 if (strace_groups_dir == NULL)
2800 return -1;
2801
2802 if (*s == '!') {
2803 ++s;
2804 trace->not_ev_qualifier = true;
2805 }
2806
2807 while (1) {
2808 if ((sep = strchr(s, ',')) != NULL)
2809 *sep = '\0';
2810
2811 list = 0;
2812 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2813 list = 1;
2814 } else {
2815 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2816 if (access(group_name, R_OK) == 0)
2817 list = 1;
2818 }
2819
2820 if (lists[list]) {
2821 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2822 } else {
2823 lists[list] = malloc(len);
2824 if (lists[list] == NULL)
2825 goto out;
2826 strcpy(lists[list], s);
2827 }
2828
2829 if (!sep)
2830 break;
2831
2832 *sep = ',';
2833 s = sep + 1;
2834 }
2835
2836 if (lists[1] != NULL) {
2837 struct strlist_config slist_config = {
2838 .dirname = strace_groups_dir,
2839 };
2840
2841 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2842 if (trace->ev_qualifier == NULL) {
2843 fputs("Not enough memory to parse event qualifier", trace->output);
2844 goto out;
2845 }
2846
2847 if (trace__validate_ev_qualifier(trace))
2848 goto out;
2849 }
2850
2851 err = 0;
2852
2853 if (lists[0]) {
2854 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2855 "event selector. use 'perf list' to list available events",
2856 parse_events_option);
2857 err = parse_events_option(&o, lists[0], 0);
2858 }
2859out:
2860 if (sep)
2861 *sep = ',';
2862
2863 return err;
2864}
2865
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002866int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002867{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002868 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002869 "perf trace [<options>] [<command>]",
2870 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002871 "perf trace record [<options>] [<command>]",
2872 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002873 NULL
2874 };
2875 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002876 .syscalls = {
2877 . max = -1,
2878 },
2879 .opts = {
2880 .target = {
2881 .uid = UINT_MAX,
2882 .uses_mmap = true,
2883 },
2884 .user_freq = UINT_MAX,
2885 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002886 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002887 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002888 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002889 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002890 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002891 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002892 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002893 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002894 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002895 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002896 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002897 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002898 OPT_CALLBACK('e', "event", &trace, "event",
2899 "event/syscall selector. use 'perf list' to list available events",
2900 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002901 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2902 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002903 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002904 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2905 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002906 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002907 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002908 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2909 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002910 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002911 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002912 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2913 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002914 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002915 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002916 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002917 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002918 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002919 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002920 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2921 "number of mmap data pages",
2922 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002923 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002924 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002925 OPT_CALLBACK(0, "duration", &trace, "float",
2926 "show only events with duration > N.M ms",
2927 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002928 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002929 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002930 OPT_BOOLEAN('T', "time", &trace.full_time,
2931 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002932 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2933 "Show only syscall summary with statistics"),
2934 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2935 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002936 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2937 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002938 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002939 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002940 OPT_CALLBACK(0, "call-graph", &trace.opts,
2941 "record_mode[,record_size]", record_callchain_help,
2942 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002943 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2944 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002945 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2946 "Set the minimum stack depth when parsing the callchain, "
2947 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002948 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2949 "Set the maximum stack depth when parsing the callchain, "
2950 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002951 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002952 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2953 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002954 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2955 "ms to wait before starting measurement after program "
2956 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002957 OPT_END()
2958 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002959 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002960 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002961 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002962 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002963 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002964
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002965 signal(SIGSEGV, sighandler_dump_stack);
2966 signal(SIGFPE, sighandler_dump_stack);
2967
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002968 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002969 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002970
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002971 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002972 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002973 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002974 goto out;
2975 }
2976
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002977 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2978 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002979
Wang Nand7888572016-04-08 15:07:24 +00002980 err = bpf__setup_stdout(trace.evlist);
2981 if (err) {
2982 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2983 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2984 goto out;
2985 }
2986
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002987 err = -1;
2988
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002989 if (trace.trace_pgfaults) {
2990 trace.opts.sample_address = true;
2991 trace.opts.sample_time = true;
2992 }
2993
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002994 if (trace.opts.mmap_pages == UINT_MAX)
2995 mmap_pages_user_set = false;
2996
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002997 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03002998 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002999 max_stack_user_set = false;
3000 }
3001
3002#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003003 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003004 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3005#endif
3006
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003007 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003008 if (!mmap_pages_user_set && geteuid() == 0)
3009 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3010
Milian Wolff566a0882016-04-08 13:34:15 +02003011 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003012 }
Milian Wolff566a0882016-04-08 13:34:15 +02003013
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003014 if (trace.evlist->nr_entries > 0)
3015 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3016
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003017 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3018 return trace__record(&trace, argc-1, &argv[1]);
3019
3020 /* summary_only implies summary option, but don't overwrite summary if set */
3021 if (trace.summary_only)
3022 trace.summary = trace.summary_only;
3023
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003024 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3025 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003026 pr_err("Please specify something to trace.\n");
3027 return -1;
3028 }
3029
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003030 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003031 pr_err("The -e option can't be used with --no-syscalls.\n");
3032 goto out;
3033 }
3034
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003035 if (output_name != NULL) {
3036 err = trace__open_output(&trace, output_name);
3037 if (err < 0) {
3038 perror("failed to create output file");
3039 goto out;
3040 }
3041 }
3042
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003043 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3044
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003045 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003046 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003047 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003048 fprintf(trace.output, "%s", bf);
3049 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003050 }
3051
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003052 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003053 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003054 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003055 fprintf(trace.output, "%s", bf);
3056 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003057 }
3058
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003059 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003060 trace.opts.target.system_wide = true;
3061
David Ahern6810fc92013-08-28 22:29:52 -06003062 if (input_name)
3063 err = trace__replay(&trace);
3064 else
3065 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003066
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003067out_close:
3068 if (output_name != NULL)
3069 fclose(trace.output);
3070out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003071 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003072}