blob: f8b7bfdf4ee71d93938c572463006a18ebcf6c75 [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 Melo5e58fcf2017-07-19 14:32:11 -03001168static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1169{
1170 int idx;
1171
1172 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1173 if (sc->arg_fmt == NULL)
1174 return -1;
1175
1176 for (idx = 0; idx < nr_args; ++idx) {
1177 if (sc->fmt)
1178 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1179 }
1180
1181 sc->nr_args = nr_args;
1182 return 0;
1183}
1184
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001185static int syscall__set_arg_fmts(struct syscall *sc)
1186{
1187 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001188 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001189
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001190 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001191 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1192 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001193
1194 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001195 (strcmp(field->name, "filename") == 0 ||
1196 strcmp(field->name, "path") == 0 ||
1197 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001198 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001199 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001200 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001201 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001202 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001203 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001204 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001205 else if ((strcmp(field->type, "int") == 0 ||
1206 strcmp(field->type, "unsigned int") == 0 ||
1207 strcmp(field->type, "long") == 0) &&
1208 (len = strlen(field->name)) >= 2 &&
1209 strcmp(field->name + len - 2, "fd") == 0) {
1210 /*
1211 * /sys/kernel/tracing/events/syscalls/sys_enter*
1212 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1213 * 65 int
1214 * 23 unsigned int
1215 * 7 unsigned long
1216 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001217 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001218 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001219 }
1220
1221 return 0;
1222}
1223
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001224static int trace__read_syscall_info(struct trace *trace, int id)
1225{
1226 char tp_name[128];
1227 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001228 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001229
1230 if (name == NULL)
1231 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001232
1233 if (id > trace->syscalls.max) {
1234 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1235
1236 if (nsyscalls == NULL)
1237 return -1;
1238
1239 if (trace->syscalls.max != -1) {
1240 memset(nsyscalls + trace->syscalls.max + 1, 0,
1241 (id - trace->syscalls.max) * sizeof(*sc));
1242 } else {
1243 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1244 }
1245
1246 trace->syscalls.table = nsyscalls;
1247 trace->syscalls.max = id;
1248 }
1249
1250 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001251 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001252
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001253 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001254
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001255 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001256 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001257
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001258 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001259 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001260 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001261 }
1262
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001263 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1264 return -1;
1265
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001266 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001267 return -1;
1268
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001269 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001270 /*
1271 * We need to check and discard the first variable '__syscall_nr'
1272 * or 'nr' that mean the syscall number. It is needless here.
1273 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1274 */
1275 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001276 sc->args = sc->args->next;
1277 --sc->nr_args;
1278 }
1279
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001280 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1281
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001282 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001283}
1284
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001285static int trace__validate_ev_qualifier(struct trace *trace)
1286{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001287 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001288 struct str_node *pos;
1289
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001290 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1291 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1292 sizeof(trace->ev_qualifier_ids.entries[0]));
1293
1294 if (trace->ev_qualifier_ids.entries == NULL) {
1295 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1296 trace->output);
1297 err = -EINVAL;
1298 goto out;
1299 }
1300
1301 i = 0;
1302
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001303 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001304 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001305 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001306
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001307 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001308 if (err == 0) {
1309 fputs("Error:\tInvalid syscall ", trace->output);
1310 err = -EINVAL;
1311 } else {
1312 fputs(", ", trace->output);
1313 }
1314
1315 fputs(sc, trace->output);
1316 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001317
1318 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001319 }
1320
1321 if (err < 0) {
1322 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1323 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001324 zfree(&trace->ev_qualifier_ids.entries);
1325 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001326 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001327out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001328 return err;
1329}
1330
David Ahern55d43bca2015-02-19 15:00:22 -05001331/*
1332 * args is to be interpreted as a series of longs but we need to handle
1333 * 8-byte unaligned accesses. args points to raw_data within the event
1334 * and raw_data is guaranteed to be 8-byte unaligned because it is
1335 * preceded by raw_size which is a u32. So we need to copy args to a temp
1336 * variable to read it. Most notably this avoids extended load instructions
1337 * on unaligned addresses
1338 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001339unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001340{
1341 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001342 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001343
1344 memcpy(&val, p, sizeof(val));
1345 return val;
1346}
1347
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001348static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1349 struct syscall_arg *arg, unsigned long val)
1350{
1351 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1352 arg->val = val;
1353 if (sc->arg_fmt[arg->idx].parm)
1354 arg->parm = sc->arg_fmt[arg->idx].parm;
1355 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1356 }
1357 return scnprintf(bf, size, "%ld", val);
1358}
1359
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001360static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001361 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001362 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001363{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001364 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001365 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001366 u8 bit = 1;
1367 struct syscall_arg arg = {
1368 .args = args,
1369 .idx = 0,
1370 .mask = 0,
1371 .trace = trace,
1372 .thread = thread,
1373 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001374 struct thread_trace *ttrace = thread__priv(thread);
1375
1376 /*
1377 * Things like fcntl will set this in its 'cmd' formatter to pick the
1378 * right formatter for the return value (an fd? file flags?), which is
1379 * not needed for syscalls that always return a given type, say an fd.
1380 */
1381 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001382
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001383 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001384 struct format_field *field;
1385
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001386 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001387 field = field->next, ++arg.idx, bit <<= 1) {
1388 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001389 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001390
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001391 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001392
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001393 /*
1394 * Suppress this argument if its value is zero and
1395 * and we don't have a string associated in an
1396 * strarray for it.
1397 */
David Ahern55d43bca2015-02-19 15:00:22 -05001398 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001399 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001400 (sc->arg_fmt[arg.idx].show_zero ||
1401 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001402 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1403 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001404 continue;
1405
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001406 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001407 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001408 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001409 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001410 } else if (IS_ERR(sc->tp_format)) {
1411 /*
1412 * If we managed to read the tracepoint /format file, then we
1413 * may end up not having any args, like with gettid(), so only
1414 * print the raw args when we didn't manage to read it.
1415 */
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001416 while (arg.idx < 6) {
1417 if (arg.mask & bit)
1418 goto next_arg;
1419 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001420 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001421 "%sarg%d: ", printed ? ", " : "", arg.idx);
1422 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1423next_arg:
1424 ++arg.idx;
1425 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001426 }
1427 }
1428
1429 return printed;
1430}
1431
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001432typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001433 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001434 struct perf_sample *sample);
1435
1436static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001437 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001438{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001439
1440 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001441
1442 /*
1443 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1444 * before that, leaving at a higher verbosity level till that is
1445 * explained. Reproduced with plain ftrace with:
1446 *
1447 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1448 * grep "NR -1 " /t/trace_pipe
1449 *
1450 * After generating some load on the machine.
1451 */
1452 if (verbose > 1) {
1453 static u64 n;
1454 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1455 id, perf_evsel__name(evsel), ++n);
1456 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001457 return NULL;
1458 }
1459
1460 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1461 trace__read_syscall_info(trace, id))
1462 goto out_cant_read;
1463
1464 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1465 goto out_cant_read;
1466
1467 return &trace->syscalls.table[id];
1468
1469out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001470 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001471 fprintf(trace->output, "Problems reading syscall %d", id);
1472 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1473 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1474 fputs(" information\n", trace->output);
1475 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001476 return NULL;
1477}
1478
David Ahernbf2575c2013-10-08 21:26:53 -06001479static void thread__update_stats(struct thread_trace *ttrace,
1480 int id, struct perf_sample *sample)
1481{
1482 struct int_node *inode;
1483 struct stats *stats;
1484 u64 duration = 0;
1485
1486 inode = intlist__findnew(ttrace->syscall_stats, id);
1487 if (inode == NULL)
1488 return;
1489
1490 stats = inode->priv;
1491 if (stats == NULL) {
1492 stats = malloc(sizeof(struct stats));
1493 if (stats == NULL)
1494 return;
1495 init_stats(stats);
1496 inode->priv = stats;
1497 }
1498
1499 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1500 duration = sample->time - ttrace->entry_time;
1501
1502 update_stats(stats, duration);
1503}
1504
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001505static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1506{
1507 struct thread_trace *ttrace;
1508 u64 duration;
1509 size_t printed;
1510
1511 if (trace->current == NULL)
1512 return 0;
1513
1514 ttrace = thread__priv(trace->current);
1515
1516 if (!ttrace->entry_pending)
1517 return 0;
1518
1519 duration = sample->time - ttrace->entry_time;
1520
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001521 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001522 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1523 ttrace->entry_pending = false;
1524
1525 return printed;
1526}
1527
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001528static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001529 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001530 struct perf_sample *sample)
1531{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001532 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001533 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001534 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001535 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001536 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001537 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001538 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001539
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001540 if (sc == NULL)
1541 return -1;
1542
David Ahern8fb598e2013-09-28 13:13:00 -06001543 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001544 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001545 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001546 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001547
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001548 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001549
1550 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001551 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001552 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001553 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001554 }
1555
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001556 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001557 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001558
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001559 ttrace->entry_time = sample->time;
1560 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001561 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001562
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001563 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001564 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001565
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001566 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001567 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001568 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001569 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001570 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001571 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001572 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001573 /* See trace__vfs_getname & trace__sys_exit */
1574 ttrace->filename.pending_open = false;
1575 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001576
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001577 if (trace->current != thread) {
1578 thread__put(trace->current);
1579 trace->current = thread__get(thread);
1580 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001581 err = 0;
1582out_put:
1583 thread__put(thread);
1584 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001585}
1586
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001587static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1588 struct perf_sample *sample,
1589 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001590{
1591 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001592
1593 if (machine__resolve(trace->host, &al, sample) < 0 ||
1594 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1595 return -1;
1596
1597 return 0;
1598}
1599
1600static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1601{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001602 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001603 const unsigned int print_opts = EVSEL__PRINT_SYM |
1604 EVSEL__PRINT_DSO |
1605 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001606
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001607 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001608}
1609
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001610static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001611 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001612 struct perf_sample *sample)
1613{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001614 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001615 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001616 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001617 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001618 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001619 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001620 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001621
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001622 if (sc == NULL)
1623 return -1;
1624
David Ahern8fb598e2013-09-28 13:13:00 -06001625 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001626 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001627 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001628 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001629
David Ahernbf2575c2013-10-08 21:26:53 -06001630 if (trace->summary)
1631 thread__update_stats(ttrace, id, sample);
1632
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001633 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001634
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001635 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001636 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1637 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001638 ++trace->stats.vfs_getname;
1639 }
1640
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001641 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001642 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001643 if (trace__filter_duration(trace, duration))
1644 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001645 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001646 } else if (trace->duration_filter)
1647 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001648
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001649 if (sample->callchain) {
1650 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1651 if (callchain_ret == 0) {
1652 if (callchain_cursor.nr < trace->min_stack)
1653 goto out;
1654 callchain_ret = 1;
1655 }
1656 }
1657
David Ahernfd2eaba2013-11-12 09:31:15 -07001658 if (trace->summary_only)
1659 goto out;
1660
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001661 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001662
1663 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001665 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001666 fprintf(trace->output, " ... [");
1667 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1668 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669 }
1670
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001671 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001672 if (ret < 0)
1673 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001674signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001675 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001676 } else if (ret < 0) {
1677errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001678 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001679 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001680 *e = audit_errno_to_name(-ret);
1681
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001682 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001683 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001684 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001685 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001686 else if (ttrace->ret_scnprintf) {
1687 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001688 struct syscall_arg arg = {
1689 .val = ret,
1690 .thread = thread,
1691 .trace = trace,
1692 };
1693 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001694 ttrace->ret_scnprintf = NULL;
1695 fprintf(trace->output, ") = %s", bf);
1696 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001697 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001698 else if (sc->fmt->errpid) {
1699 struct thread *child = machine__find_thread(trace->host, ret, ret);
1700
1701 if (child != NULL) {
1702 fprintf(trace->output, ") = %ld", ret);
1703 if (child->comm_set)
1704 fprintf(trace->output, " (%s)", thread__comm_str(child));
1705 thread__put(child);
1706 }
1707 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001708 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001709
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001710 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001711
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001712 if (callchain_ret > 0)
1713 trace__fprintf_callchain(trace, sample);
1714 else if (callchain_ret < 0)
1715 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001716out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001717 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001718 err = 0;
1719out_put:
1720 thread__put(thread);
1721 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001722}
1723
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001724static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001725 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001726 struct perf_sample *sample)
1727{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001728 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1729 struct thread_trace *ttrace;
1730 size_t filename_len, entry_str_len, to_move;
1731 ssize_t remaining_space;
1732 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001733 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001734
1735 if (!thread)
1736 goto out;
1737
1738 ttrace = thread__priv(thread);
1739 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001740 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001741
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001742 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001743 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001744 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001745
1746 if (ttrace->filename.namelen < filename_len) {
1747 char *f = realloc(ttrace->filename.name, filename_len + 1);
1748
1749 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001750 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001751
1752 ttrace->filename.namelen = filename_len;
1753 ttrace->filename.name = f;
1754 }
1755
1756 strcpy(ttrace->filename.name, filename);
1757 ttrace->filename.pending_open = true;
1758
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001759 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001760 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001761
1762 entry_str_len = strlen(ttrace->entry_str);
1763 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1764 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001765 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001766
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001767 if (filename_len > (size_t)remaining_space) {
1768 filename += filename_len - remaining_space;
1769 filename_len = remaining_space;
1770 }
1771
1772 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1773 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1774 memmove(pos + filename_len, pos, to_move);
1775 memcpy(pos, filename, filename_len);
1776
1777 ttrace->filename.ptr = 0;
1778 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001779out_put:
1780 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001781out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001782 return 0;
1783}
1784
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001785static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001786 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001787 struct perf_sample *sample)
1788{
1789 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1790 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001791 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001792 sample->pid,
1793 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001794 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001795
1796 if (ttrace == NULL)
1797 goto out_dump;
1798
1799 ttrace->runtime_ms += runtime_ms;
1800 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001801out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001802 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001803 return 0;
1804
1805out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001806 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001807 evsel->name,
1808 perf_evsel__strval(evsel, sample, "comm"),
1809 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1810 runtime,
1811 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001812 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001813}
1814
Wang Nan1d6c9402016-02-26 09:31:55 +00001815static void bpf_output__printer(enum binary_printer_ops op,
1816 unsigned int val, void *extra)
1817{
1818 FILE *output = extra;
1819 unsigned char ch = (unsigned char)val;
1820
1821 switch (op) {
1822 case BINARY_PRINT_CHAR_DATA:
1823 fprintf(output, "%c", isprint(ch) ? ch : '.');
1824 break;
1825 case BINARY_PRINT_DATA_BEGIN:
1826 case BINARY_PRINT_LINE_BEGIN:
1827 case BINARY_PRINT_ADDR:
1828 case BINARY_PRINT_NUM_DATA:
1829 case BINARY_PRINT_NUM_PAD:
1830 case BINARY_PRINT_SEP:
1831 case BINARY_PRINT_CHAR_PAD:
1832 case BINARY_PRINT_LINE_END:
1833 case BINARY_PRINT_DATA_END:
1834 default:
1835 break;
1836 }
1837}
1838
1839static void bpf_output__fprintf(struct trace *trace,
1840 struct perf_sample *sample)
1841{
1842 print_binary(sample->raw_data, sample->raw_size, 8,
1843 bpf_output__printer, trace->output);
1844}
1845
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001846static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1847 union perf_event *event __maybe_unused,
1848 struct perf_sample *sample)
1849{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001850 int callchain_ret = 0;
1851
1852 if (sample->callchain) {
1853 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1854 if (callchain_ret == 0) {
1855 if (callchain_cursor.nr < trace->min_stack)
1856 goto out;
1857 callchain_ret = 1;
1858 }
1859 }
1860
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001861 trace__printf_interrupted_entry(trace, sample);
1862 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001863
1864 if (trace->trace_syscalls)
1865 fprintf(trace->output, "( ): ");
1866
1867 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001868
Wang Nan1d6c9402016-02-26 09:31:55 +00001869 if (perf_evsel__is_bpf_output(evsel)) {
1870 bpf_output__fprintf(trace, sample);
1871 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001872 event_format__fprintf(evsel->tp_format, sample->cpu,
1873 sample->raw_data, sample->raw_size,
1874 trace->output);
1875 }
1876
1877 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001878
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001879 if (callchain_ret > 0)
1880 trace__fprintf_callchain(trace, sample);
1881 else if (callchain_ret < 0)
1882 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1883out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001884 return 0;
1885}
1886
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001887static void print_location(FILE *f, struct perf_sample *sample,
1888 struct addr_location *al,
1889 bool print_dso, bool print_sym)
1890{
1891
Namhyung Kimbb963e12017-02-17 17:17:38 +09001892 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001893 fprintf(f, "%s@", al->map->dso->long_name);
1894
Namhyung Kimbb963e12017-02-17 17:17:38 +09001895 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001896 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001897 al->addr - al->sym->start);
1898 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001899 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001900 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001901 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001902}
1903
1904static int trace__pgfault(struct trace *trace,
1905 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001906 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001907 struct perf_sample *sample)
1908{
1909 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001910 struct addr_location al;
1911 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001912 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001913 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001914 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001915
1916 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001917
1918 if (sample->callchain) {
1919 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1920 if (callchain_ret == 0) {
1921 if (callchain_cursor.nr < trace->min_stack)
1922 goto out_put;
1923 callchain_ret = 1;
1924 }
1925 }
1926
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001927 ttrace = thread__trace(thread, trace->output);
1928 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001929 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001930
1931 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1932 ttrace->pfmaj++;
1933 else
1934 ttrace->pfmin++;
1935
1936 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001937 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001938
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001939 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001940 sample->ip, &al);
1941
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001942 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001943
1944 fprintf(trace->output, "%sfault [",
1945 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1946 "maj" : "min");
1947
1948 print_location(trace->output, sample, &al, false, true);
1949
1950 fprintf(trace->output, "] => ");
1951
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001952 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001953 sample->addr, &al);
1954
1955 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001956 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001957 MAP__FUNCTION, sample->addr, &al);
1958
1959 if (al.map)
1960 map_type = 'x';
1961 else
1962 map_type = '?';
1963 }
1964
1965 print_location(trace->output, sample, &al, true, false);
1966
1967 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001968
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001969 if (callchain_ret > 0)
1970 trace__fprintf_callchain(trace, sample);
1971 else if (callchain_ret < 0)
1972 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001973out:
1974 err = 0;
1975out_put:
1976 thread__put(thread);
1977 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001978}
1979
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001980static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001981 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001982 struct perf_sample *sample)
1983{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001984 /*
1985 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1986 * and don't use sample->time unconditionally, we may end up having
1987 * some other event in the future without PERF_SAMPLE_TIME for good
1988 * reason, i.e. we may not be interested in its timestamps, just in
1989 * it taking place, picking some piece of information when it
1990 * appears in our event stream (vfs_getname comes to mind).
1991 */
1992 if (trace->base_time == 0 && !trace->full_time &&
1993 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001994 trace->base_time = sample->time;
1995}
1996
David Ahern6810fc92013-08-28 22:29:52 -06001997static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001998 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06001999 struct perf_sample *sample,
2000 struct perf_evsel *evsel,
2001 struct machine *machine __maybe_unused)
2002{
2003 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002004 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002005 int err = 0;
2006
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002007 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002008
David Ahernaa07df62016-11-25 09:29:52 -07002009 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2010 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002011 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002012
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002013 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002014
David Ahern31605652013-12-04 19:41:41 -07002015 if (handler) {
2016 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002017 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002018 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002019out:
2020 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002021 return err;
2022}
2023
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002024static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002025{
2026 unsigned int rec_argc, i, j;
2027 const char **rec_argv;
2028 const char * const record_args[] = {
2029 "record",
2030 "-R",
2031 "-m", "1024",
2032 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002033 };
2034
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002035 const char * const sc_args[] = { "-e", };
2036 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2037 const char * const majpf_args[] = { "-e", "major-faults" };
2038 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2039 const char * const minpf_args[] = { "-e", "minor-faults" };
2040 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2041
David Ahern9aca7f12013-12-04 19:41:39 -07002042 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002043 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2044 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002045 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2046
2047 if (rec_argv == NULL)
2048 return -ENOMEM;
2049
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002050 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002051 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002052 rec_argv[j++] = record_args[i];
2053
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002054 if (trace->trace_syscalls) {
2055 for (i = 0; i < sc_args_nr; i++)
2056 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002057
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002058 /* event string may be different for older kernels - e.g., RHEL6 */
2059 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2060 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2061 else if (is_valid_tracepoint("syscalls:sys_enter"))
2062 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2063 else {
2064 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2065 return -1;
2066 }
David Ahern9aca7f12013-12-04 19:41:39 -07002067 }
David Ahern9aca7f12013-12-04 19:41:39 -07002068
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002069 if (trace->trace_pgfaults & TRACE_PFMAJ)
2070 for (i = 0; i < majpf_args_nr; i++)
2071 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002072
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002073 if (trace->trace_pgfaults & TRACE_PFMIN)
2074 for (i = 0; i < minpf_args_nr; i++)
2075 rec_argv[j++] = minpf_args[i];
2076
2077 for (i = 0; i < (unsigned int)argc; i++)
2078 rec_argv[j++] = argv[i];
2079
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002080 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002081}
2082
David Ahernbf2575c2013-10-08 21:26:53 -06002083static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2084
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002085static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002086{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002087 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002088
2089 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002090 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002091
2092 if (perf_evsel__field(evsel, "pathname") == NULL) {
2093 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002094 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002095 }
2096
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002097 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002098 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002099 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002100}
2101
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002102static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002103{
2104 struct perf_evsel *evsel;
2105 struct perf_event_attr attr = {
2106 .type = PERF_TYPE_SOFTWARE,
2107 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002108 };
2109
2110 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002111 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002112
2113 event_attr_init(&attr);
2114
2115 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002116 if (evsel)
2117 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002118
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002119 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002120}
2121
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002122static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2123{
2124 const u32 type = event->header.type;
2125 struct perf_evsel *evsel;
2126
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002127 if (type != PERF_RECORD_SAMPLE) {
2128 trace__process_event(trace, trace->host, event, sample);
2129 return;
2130 }
2131
2132 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2133 if (evsel == NULL) {
2134 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2135 return;
2136 }
2137
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002138 trace__set_base_time(trace, evsel, sample);
2139
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002140 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2141 sample->raw_data == NULL) {
2142 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2143 perf_evsel__name(evsel), sample->tid,
2144 sample->cpu, sample->raw_size);
2145 } else {
2146 tracepoint_handler handler = evsel->handler;
2147 handler(trace, evsel, event, sample);
2148 }
2149}
2150
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002151static int trace__add_syscall_newtp(struct trace *trace)
2152{
2153 int ret = -1;
2154 struct perf_evlist *evlist = trace->evlist;
2155 struct perf_evsel *sys_enter, *sys_exit;
2156
2157 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2158 if (sys_enter == NULL)
2159 goto out;
2160
2161 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2162 goto out_delete_sys_enter;
2163
2164 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2165 if (sys_exit == NULL)
2166 goto out_delete_sys_enter;
2167
2168 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2169 goto out_delete_sys_exit;
2170
2171 perf_evlist__add(evlist, sys_enter);
2172 perf_evlist__add(evlist, sys_exit);
2173
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002174 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002175 /*
2176 * We're interested only in the user space callchain
2177 * leading to the syscall, allow overriding that for
2178 * debugging reasons using --kernel_syscall_callchains
2179 */
2180 sys_exit->attr.exclude_callchain_kernel = 1;
2181 }
2182
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002183 trace->syscalls.events.sys_enter = sys_enter;
2184 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002185
2186 ret = 0;
2187out:
2188 return ret;
2189
2190out_delete_sys_exit:
2191 perf_evsel__delete_priv(sys_exit);
2192out_delete_sys_enter:
2193 perf_evsel__delete_priv(sys_enter);
2194 goto out;
2195}
2196
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002197static int trace__set_ev_qualifier_filter(struct trace *trace)
2198{
2199 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002200 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002201 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2202 trace->ev_qualifier_ids.nr,
2203 trace->ev_qualifier_ids.entries);
2204
2205 if (filter == NULL)
2206 goto out_enomem;
2207
Mathieu Poirier3541c032016-09-16 08:44:04 -06002208 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2209 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002210 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002211 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002212 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002213
2214 free(filter);
2215out:
2216 return err;
2217out_enomem:
2218 errno = ENOMEM;
2219 goto out;
2220}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002221
Namhyung Kimf15eb532012-10-05 14:02:16 +09002222static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002223{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002224 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002225 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002226 int err = -1, i;
2227 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002228 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002229 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002230
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002231 trace->live = true;
2232
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002233 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002234 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002235
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002236 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002237 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002238
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002239 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2240 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2241 if (pgfault_maj == NULL)
2242 goto out_error_mem;
2243 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002244 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002245
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002246 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2247 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2248 if (pgfault_min == NULL)
2249 goto out_error_mem;
2250 perf_evlist__add(evlist, pgfault_min);
2251 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002252
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002253 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002254 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2255 trace__sched_stat_runtime))
2256 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002257
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002258 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2259 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002260 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002261 goto out_delete_evlist;
2262 }
2263
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002264 err = trace__symbols_init(trace, evlist);
2265 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002266 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002267 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002268 }
2269
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002270 perf_evlist__config(evlist, &trace->opts, NULL);
2271
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002272 if (callchain_param.enabled) {
2273 bool use_identifier = false;
2274
2275 if (trace->syscalls.events.sys_exit) {
2276 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2277 &trace->opts, &callchain_param);
2278 use_identifier = true;
2279 }
2280
2281 if (pgfault_maj) {
2282 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2283 use_identifier = true;
2284 }
2285
2286 if (pgfault_min) {
2287 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2288 use_identifier = true;
2289 }
2290
2291 if (use_identifier) {
2292 /*
2293 * Now we have evsels with different sample_ids, use
2294 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2295 * from a fixed position in each ring buffer record.
2296 *
2297 * As of this the changeset introducing this comment, this
2298 * isn't strictly needed, as the fields that can come before
2299 * PERF_SAMPLE_ID are all used, but we'll probably disable
2300 * some of those for things like copying the payload of
2301 * pointer syscall arguments, and for vfs_getname we don't
2302 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2303 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2304 */
2305 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2306 perf_evlist__reset_sample_bit(evlist, ID);
2307 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002308 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002309
Namhyung Kimf15eb532012-10-05 14:02:16 +09002310 signal(SIGCHLD, sig_handler);
2311 signal(SIGINT, sig_handler);
2312
2313 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002314 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002315 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002316 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002317 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002318 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002319 }
2320 }
2321
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002322 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002323 if (err < 0)
2324 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002325
Wang Nanba504232016-02-26 09:31:54 +00002326 err = bpf__apply_obj_config();
2327 if (err) {
2328 char errbuf[BUFSIZ];
2329
2330 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2331 pr_err("ERROR: Apply config to BPF failed: %s\n",
2332 errbuf);
2333 goto out_error_open;
2334 }
2335
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002336 /*
2337 * Better not use !target__has_task() here because we need to cover the
2338 * case where no threads were specified in the command line, but a
2339 * workload was, and in that case we will fill in the thread_map when
2340 * we fork the workload in perf_evlist__prepare_workload.
2341 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002342 if (trace->filter_pids.nr > 0)
2343 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002344 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002345 err = perf_evlist__set_filter_pid(evlist, getpid());
2346
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002347 if (err < 0)
2348 goto out_error_mem;
2349
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002350 if (trace->ev_qualifier_ids.nr > 0) {
2351 err = trace__set_ev_qualifier_filter(trace);
2352 if (err < 0)
2353 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002354
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002355 pr_debug("event qualifier tracepoint filter: %s\n",
2356 trace->syscalls.events.sys_exit->filter);
2357 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002358
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002359 err = perf_evlist__apply_filters(evlist, &evsel);
2360 if (err < 0)
2361 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002362
Jiri Olsaf8850372013-11-28 17:57:22 +01002363 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002364 if (err < 0)
2365 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002366
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002367 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002368 perf_evlist__enable(evlist);
2369
Namhyung Kimf15eb532012-10-05 14:02:16 +09002370 if (forks)
2371 perf_evlist__start_workload(evlist);
2372
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002373 if (trace->opts.initial_delay) {
2374 usleep(trace->opts.initial_delay * 1000);
2375 perf_evlist__enable(evlist);
2376 }
2377
Jiri Olsae13798c2015-06-23 00:36:02 +02002378 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002379 evlist->threads->nr > 1 ||
2380 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002381again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002382 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002383
2384 for (i = 0; i < evlist->nr_mmaps; i++) {
2385 union perf_event *event;
2386
2387 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002388 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002389
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002390 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002391
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392 err = perf_evlist__parse_sample(evlist, event, &sample);
2393 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002394 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002395 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002396 }
2397
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002398 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002399next_event:
2400 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002401
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002402 if (interrupted)
2403 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002404
2405 if (done && !draining) {
2406 perf_evlist__disable(evlist);
2407 draining = true;
2408 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002409 }
2410 }
2411
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002412 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002413 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002414
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002415 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2416 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2417 draining = true;
2418
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002419 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002420 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002421 } else {
2422 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002423 }
2424
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002425out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002426 thread__zput(trace->current);
2427
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002428 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002430 if (!err) {
2431 if (trace->summary)
2432 trace__fprintf_thread_summary(trace, trace->output);
2433
2434 if (trace->show_tool_stats) {
2435 fprintf(trace->output, "Stats:\n "
2436 " vfs_getname : %" PRIu64 "\n"
2437 " proc_getname: %" PRIu64 "\n",
2438 trace->stats.vfs_getname,
2439 trace->stats.proc_getname);
2440 }
2441 }
David Ahernbf2575c2013-10-08 21:26:53 -06002442
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002443out_delete_evlist:
2444 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002445 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002446 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002447 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002448{
2449 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002450
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002451out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002452 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002453 goto out_error;
2454
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002455out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002456 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002457 goto out_error;
2458
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002459out_error_mmap:
2460 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2461 goto out_error;
2462
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002463out_error_open:
2464 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2465
2466out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002467 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302468 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002469
2470out_error_apply_filters:
2471 fprintf(trace->output,
2472 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2473 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002474 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002475 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002476}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002477out_error_mem:
2478 fprintf(trace->output, "Not enough memory to run!\n");
2479 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002480
2481out_errno:
2482 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2483 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002484}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002485
David Ahern6810fc92013-08-28 22:29:52 -06002486static int trace__replay(struct trace *trace)
2487{
2488 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002489 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002490 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002491 struct perf_data_file file = {
2492 .path = input_name,
2493 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002494 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002495 };
David Ahern6810fc92013-08-28 22:29:52 -06002496 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002497 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002498 int err = -1;
2499
2500 trace->tool.sample = trace__process_sample;
2501 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002502 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002503 trace->tool.comm = perf_event__process_comm;
2504 trace->tool.exit = perf_event__process_exit;
2505 trace->tool.fork = perf_event__process_fork;
2506 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302507 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002508 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302509 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002510
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002511 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002512 trace->tool.ordering_requires_timestamps = true;
2513
2514 /* add tid to output */
2515 trace->multiple_threads = true;
2516
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002517 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002518 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002519 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002520
David Ahernaa07df62016-11-25 09:29:52 -07002521 if (trace->opts.target.pid)
2522 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2523
2524 if (trace->opts.target.tid)
2525 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2526
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002527 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002528 goto out;
2529
David Ahern8fb598e2013-09-28 13:13:00 -06002530 trace->host = &session->machines.host;
2531
David Ahern6810fc92013-08-28 22:29:52 -06002532 err = perf_session__set_tracepoints_handlers(session, handlers);
2533 if (err)
2534 goto out;
2535
Namhyung Kim003824e2013-11-12 15:25:00 +09002536 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2537 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002538 /* older kernels have syscalls tp versus raw_syscalls */
2539 if (evsel == NULL)
2540 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2541 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002542
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002543 if (evsel &&
2544 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2545 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002546 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2547 goto out;
2548 }
2549
2550 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2551 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002552 if (evsel == NULL)
2553 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2554 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002555 if (evsel &&
2556 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2557 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002558 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002559 goto out;
2560 }
2561
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002562 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002563 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2564 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2565 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2566 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2567 evsel->handler = trace__pgfault;
2568 }
2569
David Ahern6810fc92013-08-28 22:29:52 -06002570 setup_pager();
2571
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002572 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002573 if (err)
2574 pr_err("Failed to process events, error %d", err);
2575
David Ahernbf2575c2013-10-08 21:26:53 -06002576 else if (trace->summary)
2577 trace__fprintf_thread_summary(trace, trace->output);
2578
David Ahern6810fc92013-08-28 22:29:52 -06002579out:
2580 perf_session__delete(session);
2581
2582 return err;
2583}
2584
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002585static size_t trace__fprintf_threads_header(FILE *fp)
2586{
2587 size_t printed;
2588
Pekka Enberg99ff7152013-11-12 16:42:14 +02002589 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002590
2591 return printed;
2592}
2593
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002594DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2595 struct stats *stats;
2596 double msecs;
2597 int syscall;
2598)
2599{
2600 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2601 struct stats *stats = source->priv;
2602
2603 entry->syscall = source->i;
2604 entry->stats = stats;
2605 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2606}
2607
David Ahernbf2575c2013-10-08 21:26:53 -06002608static size_t thread__dump_stats(struct thread_trace *ttrace,
2609 struct trace *trace, FILE *fp)
2610{
David Ahernbf2575c2013-10-08 21:26:53 -06002611 size_t printed = 0;
2612 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002613 struct rb_node *nd;
2614 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002615
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002616 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002617 return 0;
2618
2619 printed += fprintf(fp, "\n");
2620
Milian Wolff834fd462015-08-06 11:24:29 +02002621 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2622 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2623 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002624
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002625 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002626 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002627 if (stats) {
2628 double min = (double)(stats->min) / NSEC_PER_MSEC;
2629 double max = (double)(stats->max) / NSEC_PER_MSEC;
2630 double avg = avg_stats(stats);
2631 double pct;
2632 u64 n = (u64) stats->n;
2633
2634 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2635 avg /= NSEC_PER_MSEC;
2636
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002637 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002638 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002639 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002640 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002641 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002642 }
David Ahernbf2575c2013-10-08 21:26:53 -06002643 }
2644
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002645 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002646 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002647
2648 return printed;
2649}
2650
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002651static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002652{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002653 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002654 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002655 double ratio;
2656
2657 if (ttrace == NULL)
2658 return 0;
2659
2660 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2661
Pekka Enberg15e65c62013-11-14 18:43:30 +02002662 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002663 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002664 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002665 if (ttrace->pfmaj)
2666 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2667 if (ttrace->pfmin)
2668 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002669 if (trace->sched)
2670 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2671 else if (fputc('\n', fp) != EOF)
2672 ++printed;
2673
David Ahernbf2575c2013-10-08 21:26:53 -06002674 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002675
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002676 return printed;
2677}
David Ahern896cbb52013-09-28 13:12:59 -06002678
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002679static unsigned long thread__nr_events(struct thread_trace *ttrace)
2680{
2681 return ttrace ? ttrace->nr_events : 0;
2682}
2683
2684DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2685 struct thread *thread;
2686)
2687{
2688 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002689}
2690
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002691static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2692{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002693 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2694 size_t printed = trace__fprintf_threads_header(fp);
2695 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002696
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002697 if (threads == NULL) {
2698 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2699 return 0;
2700 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002701
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002702 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002703 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2704
2705 resort_rb__delete(threads);
2706
2707 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002708}
2709
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002710static int trace__set_duration(const struct option *opt, const char *str,
2711 int unset __maybe_unused)
2712{
2713 struct trace *trace = opt->value;
2714
2715 trace->duration_filter = atof(str);
2716 return 0;
2717}
2718
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002719static int trace__set_filter_pids(const struct option *opt, const char *str,
2720 int unset __maybe_unused)
2721{
2722 int ret = -1;
2723 size_t i;
2724 struct trace *trace = opt->value;
2725 /*
2726 * FIXME: introduce a intarray class, plain parse csv and create a
2727 * { int nr, int entries[] } struct...
2728 */
2729 struct intlist *list = intlist__new(str);
2730
2731 if (list == NULL)
2732 return -1;
2733
2734 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2735 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2736
2737 if (trace->filter_pids.entries == NULL)
2738 goto out;
2739
2740 trace->filter_pids.entries[0] = getpid();
2741
2742 for (i = 1; i < trace->filter_pids.nr; ++i)
2743 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2744
2745 intlist__delete(list);
2746 ret = 0;
2747out:
2748 return ret;
2749}
2750
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002751static int trace__open_output(struct trace *trace, const char *filename)
2752{
2753 struct stat st;
2754
2755 if (!stat(filename, &st) && st.st_size) {
2756 char oldname[PATH_MAX];
2757
2758 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2759 unlink(oldname);
2760 rename(filename, oldname);
2761 }
2762
2763 trace->output = fopen(filename, "w");
2764
2765 return trace->output == NULL ? -errno : 0;
2766}
2767
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002768static int parse_pagefaults(const struct option *opt, const char *str,
2769 int unset __maybe_unused)
2770{
2771 int *trace_pgfaults = opt->value;
2772
2773 if (strcmp(str, "all") == 0)
2774 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2775 else if (strcmp(str, "maj") == 0)
2776 *trace_pgfaults |= TRACE_PFMAJ;
2777 else if (strcmp(str, "min") == 0)
2778 *trace_pgfaults |= TRACE_PFMIN;
2779 else
2780 return -1;
2781
2782 return 0;
2783}
2784
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002785static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2786{
2787 struct perf_evsel *evsel;
2788
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002789 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002790 evsel->handler = handler;
2791}
2792
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002793/*
2794 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2795 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2796 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2797 *
2798 * It'd be better to introduce a parse_options() variant that would return a
2799 * list with the terms it didn't match to an event...
2800 */
2801static int trace__parse_events_option(const struct option *opt, const char *str,
2802 int unset __maybe_unused)
2803{
2804 struct trace *trace = (struct trace *)opt->value;
2805 const char *s = str;
2806 char *sep = NULL, *lists[2] = { NULL, NULL, };
2807 int len = strlen(str), err = -1, list;
2808 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2809 char group_name[PATH_MAX];
2810
2811 if (strace_groups_dir == NULL)
2812 return -1;
2813
2814 if (*s == '!') {
2815 ++s;
2816 trace->not_ev_qualifier = true;
2817 }
2818
2819 while (1) {
2820 if ((sep = strchr(s, ',')) != NULL)
2821 *sep = '\0';
2822
2823 list = 0;
2824 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2825 list = 1;
2826 } else {
2827 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2828 if (access(group_name, R_OK) == 0)
2829 list = 1;
2830 }
2831
2832 if (lists[list]) {
2833 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2834 } else {
2835 lists[list] = malloc(len);
2836 if (lists[list] == NULL)
2837 goto out;
2838 strcpy(lists[list], s);
2839 }
2840
2841 if (!sep)
2842 break;
2843
2844 *sep = ',';
2845 s = sep + 1;
2846 }
2847
2848 if (lists[1] != NULL) {
2849 struct strlist_config slist_config = {
2850 .dirname = strace_groups_dir,
2851 };
2852
2853 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2854 if (trace->ev_qualifier == NULL) {
2855 fputs("Not enough memory to parse event qualifier", trace->output);
2856 goto out;
2857 }
2858
2859 if (trace__validate_ev_qualifier(trace))
2860 goto out;
2861 }
2862
2863 err = 0;
2864
2865 if (lists[0]) {
2866 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2867 "event selector. use 'perf list' to list available events",
2868 parse_events_option);
2869 err = parse_events_option(&o, lists[0], 0);
2870 }
2871out:
2872 if (sep)
2873 *sep = ',';
2874
2875 return err;
2876}
2877
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002878int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002879{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002880 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002881 "perf trace [<options>] [<command>]",
2882 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002883 "perf trace record [<options>] [<command>]",
2884 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002885 NULL
2886 };
2887 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002888 .syscalls = {
2889 . max = -1,
2890 },
2891 .opts = {
2892 .target = {
2893 .uid = UINT_MAX,
2894 .uses_mmap = true,
2895 },
2896 .user_freq = UINT_MAX,
2897 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002898 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002899 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002900 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002901 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002902 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002903 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002904 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002905 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002906 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002907 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002908 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002909 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002910 OPT_CALLBACK('e', "event", &trace, "event",
2911 "event/syscall selector. use 'perf list' to list available events",
2912 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002913 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2914 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002915 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002916 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2917 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002918 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002919 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002920 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2921 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002922 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002923 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002924 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2925 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002926 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002927 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002928 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002929 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002930 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002931 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002932 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2933 "number of mmap data pages",
2934 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002935 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002936 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002937 OPT_CALLBACK(0, "duration", &trace, "float",
2938 "show only events with duration > N.M ms",
2939 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002940 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002941 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002942 OPT_BOOLEAN('T', "time", &trace.full_time,
2943 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002944 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2945 "Show only syscall summary with statistics"),
2946 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2947 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002948 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2949 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002950 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002951 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002952 OPT_CALLBACK(0, "call-graph", &trace.opts,
2953 "record_mode[,record_size]", record_callchain_help,
2954 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002955 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2956 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002957 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2958 "Set the minimum stack depth when parsing the callchain, "
2959 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002960 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2961 "Set the maximum stack depth when parsing the callchain, "
2962 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002963 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002964 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2965 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002966 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2967 "ms to wait before starting measurement after program "
2968 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002969 OPT_END()
2970 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002971 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002972 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002973 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002974 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002975 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002976
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002977 signal(SIGSEGV, sighandler_dump_stack);
2978 signal(SIGFPE, sighandler_dump_stack);
2979
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002980 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002981 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002982
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002983 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002984 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002985 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002986 goto out;
2987 }
2988
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002989 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2990 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002991
Wang Nand7888572016-04-08 15:07:24 +00002992 err = bpf__setup_stdout(trace.evlist);
2993 if (err) {
2994 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2995 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2996 goto out;
2997 }
2998
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03002999 err = -1;
3000
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003001 if (trace.trace_pgfaults) {
3002 trace.opts.sample_address = true;
3003 trace.opts.sample_time = true;
3004 }
3005
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003006 if (trace.opts.mmap_pages == UINT_MAX)
3007 mmap_pages_user_set = false;
3008
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003009 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003010 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003011 max_stack_user_set = false;
3012 }
3013
3014#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003015 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003016 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3017#endif
3018
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003019 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003020 if (!mmap_pages_user_set && geteuid() == 0)
3021 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3022
Milian Wolff566a0882016-04-08 13:34:15 +02003023 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003024 }
Milian Wolff566a0882016-04-08 13:34:15 +02003025
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003026 if (trace.evlist->nr_entries > 0)
3027 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3028
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003029 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3030 return trace__record(&trace, argc-1, &argv[1]);
3031
3032 /* summary_only implies summary option, but don't overwrite summary if set */
3033 if (trace.summary_only)
3034 trace.summary = trace.summary_only;
3035
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003036 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3037 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003038 pr_err("Please specify something to trace.\n");
3039 return -1;
3040 }
3041
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003042 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003043 pr_err("The -e option can't be used with --no-syscalls.\n");
3044 goto out;
3045 }
3046
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003047 if (output_name != NULL) {
3048 err = trace__open_output(&trace, output_name);
3049 if (err < 0) {
3050 perror("failed to create output file");
3051 goto out;
3052 }
3053 }
3054
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003055 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3056
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003057 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003058 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003059 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003060 fprintf(trace.output, "%s", bf);
3061 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003062 }
3063
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003064 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003065 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003066 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003067 fprintf(trace.output, "%s", bf);
3068 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003069 }
3070
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003071 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003072 trace.opts.target.system_wide = true;
3073
David Ahern6810fc92013-08-28 22:29:52 -06003074 if (input_name)
3075 err = trace__replay(&trace);
3076 else
3077 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003078
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003079out_close:
3080 if (output_name != NULL)
3081 fclose(trace.output);
3082out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003083 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003084}