blob: b842bd93457fbdba1662e00f7e0d6c64914c305d [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 Melo514f1c62012-09-26 20:05:56 -0300614 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300615 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300616 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300617 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300618} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300619 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300620 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300621 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 { .name = "bpf", .errmsg = true,
623 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300624 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300625 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300626 { .name = "chdir", .errmsg = true, },
627 { .name = "chmod", .errmsg = true, },
628 { .name = "chroot", .errmsg = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300629 { .name = "clock_gettime", .errmsg = true,
630 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300631 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300632 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300633 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300634 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300635 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300636 { .name = "dup", .errmsg = true, },
637 { .name = "dup2", .errmsg = true, },
638 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300639 { .name = "epoll_ctl", .errmsg = true,
640 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300641 { .name = "eventfd2", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300642 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300643 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300644 { .name = "fadvise64", .errmsg = true, },
645 { .name = "fallocate", .errmsg = true, },
646 { .name = "fchdir", .errmsg = true, },
647 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300648 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300649 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300650 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300651 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300652 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300653 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300654 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
655 .parm = &strarrays__fcntl_cmds_arrays, /* cmd */ },
656 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300657 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300658 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300659 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300660 { .name = "fsetxattr", .errmsg = true, },
661 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300662 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300663 { .name = "fstatfs", .errmsg = true, },
664 { .name = "fsync", .errmsg = true, },
665 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300666 { .name = "futex", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300667 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300668 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300669 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300670 { .name = "getdents", .errmsg = true, },
671 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300672 { .name = "getitimer", .errmsg = true,
673 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300674 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300675 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300676 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300677 { .name = "getrandom", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300678 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
679 { .name = "getrlimit", .errmsg = true,
680 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300681 { .name = "getxattr", .errmsg = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300683 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300684 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300685#if defined(__i386__) || defined(__x86_64__)
686/*
687 * FIXME: Make this available to all arches.
688 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300689 [1] = { .scnprintf = SCA_STRHEXARRAY, /* cmd */
690 .parm = &strarray__tioctls, },
691 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300692#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300693 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300694#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300695 { .name = "keyctl", .errmsg = true,
696 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300697 { .name = "kill", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300698 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300699 { .name = "lchown", .errmsg = true, },
700 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300701 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300702 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300703 { .name = "listxattr", .errmsg = true, },
704 { .name = "llistxattr", .errmsg = true, },
705 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300706 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300707 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300708 { .name = "lsetxattr", .errmsg = true, },
709 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
710 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300711 { .name = "madvise", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
713 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300714 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300715 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300717 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300718 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300719 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300720 { .name = "mlock", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300721 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300722 { .name = "mlockall", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300723 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300724 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200725/* The standard mmap maps to old_mmap on s390x */
726#if defined(__s390x__)
727 .alias = "old_mmap",
728#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300729 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
730 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
731 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300732 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300733 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
734 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300735 { .name = "mq_unlink", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300736 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300737 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300738 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
739 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
740 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300741 { .name = "munlock", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300742 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300743 { .name = "munmap", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300744 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300745 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300746 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300747 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300748 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300749 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300750 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300751 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300752 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
753 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300754 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
756 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300757 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300758 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
759 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
760 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300761 { .name = "pipe2", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300762 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300763 { .name = "poll", .errmsg = true, .timeout = true, },
764 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300765 { .name = "pread", .errmsg = true, .alias = "pread64", },
766 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 { .name = "prlimit64", .errmsg = true,
768 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300769 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
770 { .name = "pwritev", .errmsg = true, },
771 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300772 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300773 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300774 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300775 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300776 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300777 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300778 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300779 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300780 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300781 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300782 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300783 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300784 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300785 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300786 { .name = "rt_sigaction", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300787 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
788 { .name = "rt_sigprocmask", .errmsg = true,
789 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300790 { .name = "rt_sigqueueinfo", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300791 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300792 { .name = "rt_tgsigqueueinfo", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300793 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300794 { .name = "sched_getattr", .errmsg = true, },
795 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300796 { .name = "sched_setscheduler", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300797 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300798 { .name = "seccomp", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300799 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
800 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300801 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300802 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300803 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300804 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300805 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300806 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300807 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300808 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300809 { .name = "setitimer", .errmsg = true,
810 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300811 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300812 { .name = "setrlimit", .errmsg = true,
813 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300814 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300815 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300816 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300817 .arg = { [0] = STRARRAY(family, socket_families),
818 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300819 { .name = "socketpair", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300820 .arg = { [0] = STRARRAY(family, socket_families),
821 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300822 { .name = "stat", .errmsg = true, .alias = "newstat", },
823 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300824 { .name = "statx", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300825 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
826 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
827 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300828 { .name = "swapoff", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300829 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300830 { .name = "swapon", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300831 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300832 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300833 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300834 { .name = "tgkill", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300835 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300836 { .name = "tkill", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300837 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300838 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300839 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300840 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300841 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300842 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300843 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300844 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300845 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300846 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300847 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300848 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300849 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300850 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300851 { .name = "write", .errmsg = true, },
852 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300853};
854
855static int syscall_fmt__cmp(const void *name, const void *fmtp)
856{
857 const struct syscall_fmt *fmt = fmtp;
858 return strcmp(name, fmt->name);
859}
860
861static struct syscall_fmt *syscall_fmt__find(const char *name)
862{
863 const int nmemb = ARRAY_SIZE(syscall_fmts);
864 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
865}
866
867struct syscall {
868 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300869 int nr_args;
870 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300871 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300872 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300873 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300874 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300875};
876
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300877/*
878 * We need to have this 'calculated' boolean because in some cases we really
879 * don't know what is the duration of a syscall, for instance, when we start
880 * a session and some threads are waiting for a syscall to finish, say 'poll',
881 * in which case all we can do is to print "( ? ) for duration and for the
882 * start timestamp.
883 */
884static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200885{
886 double duration = (double)t / NSEC_PER_MSEC;
887 size_t printed = fprintf(fp, "(");
888
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300889 if (!calculated)
890 printed += fprintf(fp, " ? ");
891 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200892 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
893 else if (duration >= 0.01)
894 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
895 else
896 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300897 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200898}
899
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300900/**
901 * filename.ptr: The filename char pointer that will be vfs_getname'd
902 * filename.entry_str_pos: Where to insert the string translated from
903 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300904 * ret_scnprintf: syscall args may set this to a different syscall return
905 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300906 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300907struct thread_trace {
908 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300910 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400911 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300913 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300914 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300915 struct {
916 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300917 short int entry_str_pos;
918 bool pending_open;
919 unsigned int namelen;
920 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300921 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300922 struct {
923 int max;
924 char **table;
925 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600926
927 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300928};
929
930static struct thread_trace *thread_trace__new(void)
931{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300932 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
933
934 if (ttrace)
935 ttrace->paths.max = -1;
936
David Ahernbf2575c2013-10-08 21:26:53 -0600937 ttrace->syscall_stats = intlist__new(NULL);
938
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300939 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300940}
941
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300942static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300943{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300944 struct thread_trace *ttrace;
945
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300946 if (thread == NULL)
947 goto fail;
948
Namhyung Kim89dceb22014-10-06 09:46:03 +0900949 if (thread__priv(thread) == NULL)
950 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300951
Namhyung Kim89dceb22014-10-06 09:46:03 +0900952 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300953 goto fail;
954
Namhyung Kim89dceb22014-10-06 09:46:03 +0900955 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300956 ++ttrace->nr_events;
957
958 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300959fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300960 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300961 "WARNING: not enough memory, dropping samples!\n");
962 return NULL;
963}
964
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300965
966void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300967 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300968{
969 struct thread_trace *ttrace = thread__priv(arg->thread);
970
971 ttrace->ret_scnprintf = ret_scnprintf;
972}
973
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400974#define TRACE_PFMAJ (1 << 0)
975#define TRACE_PFMIN (1 << 1)
976
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300977static const size_t trace__entry_str_size = 2048;
978
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300979static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300980{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900981 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300982
983 if (fd > ttrace->paths.max) {
984 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
985
986 if (npath == NULL)
987 return -1;
988
989 if (ttrace->paths.max != -1) {
990 memset(npath + ttrace->paths.max + 1, 0,
991 (fd - ttrace->paths.max) * sizeof(char *));
992 } else {
993 memset(npath, 0, (fd + 1) * sizeof(char *));
994 }
995
996 ttrace->paths.table = npath;
997 ttrace->paths.max = fd;
998 }
999
1000 ttrace->paths.table[fd] = strdup(pathname);
1001
1002 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1003}
1004
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001005static int thread__read_fd_path(struct thread *thread, int fd)
1006{
1007 char linkname[PATH_MAX], pathname[PATH_MAX];
1008 struct stat st;
1009 int ret;
1010
1011 if (thread->pid_ == thread->tid) {
1012 scnprintf(linkname, sizeof(linkname),
1013 "/proc/%d/fd/%d", thread->pid_, fd);
1014 } else {
1015 scnprintf(linkname, sizeof(linkname),
1016 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1017 }
1018
1019 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1020 return -1;
1021
1022 ret = readlink(linkname, pathname, sizeof(pathname));
1023
1024 if (ret < 0 || ret > st.st_size)
1025 return -1;
1026
1027 pathname[ret] = '\0';
1028 return trace__set_fd_pathname(thread, fd, pathname);
1029}
1030
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001031static const char *thread__fd_path(struct thread *thread, int fd,
1032 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001033{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001034 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001035
1036 if (ttrace == NULL)
1037 return NULL;
1038
1039 if (fd < 0)
1040 return NULL;
1041
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001042 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001043 if (!trace->live)
1044 return NULL;
1045 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001046 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001047 return NULL;
1048 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001049
1050 return ttrace->paths.table[fd];
1051}
1052
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001053size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054{
1055 int fd = arg->val;
1056 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001057 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001058
1059 if (path)
1060 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1061
1062 return printed;
1063}
1064
1065static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1066 struct syscall_arg *arg)
1067{
1068 int fd = arg->val;
1069 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001070 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001071
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001072 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1073 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001074
1075 return printed;
1076}
1077
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001078static void thread__set_filename_pos(struct thread *thread, const char *bf,
1079 unsigned long ptr)
1080{
1081 struct thread_trace *ttrace = thread__priv(thread);
1082
1083 ttrace->filename.ptr = ptr;
1084 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1085}
1086
1087static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1088 struct syscall_arg *arg)
1089{
1090 unsigned long ptr = arg->val;
1091
1092 if (!arg->trace->vfs_getname)
1093 return scnprintf(bf, size, "%#x", ptr);
1094
1095 thread__set_filename_pos(arg->thread, bf, ptr);
1096 return 0;
1097}
1098
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001099static bool trace__filter_duration(struct trace *trace, double t)
1100{
1101 return t < (trace->duration_filter * NSEC_PER_MSEC);
1102}
1103
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001104static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105{
1106 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1107
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001108 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109}
1110
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001111/*
1112 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1113 * using ttrace->entry_time for a thread that receives a sys_exit without
1114 * first having received a sys_enter ("poll" issued before tracing session
1115 * starts, lost sys_enter exit due to ring buffer overflow).
1116 */
1117static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1118{
1119 if (tstamp > 0)
1120 return __trace__fprintf_tstamp(trace, tstamp, fp);
1121
1122 return fprintf(fp, " ? ");
1123}
1124
Namhyung Kimf15eb532012-10-05 14:02:16 +09001125static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001126static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001127
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001128static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001129{
1130 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001131 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001132}
1133
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001134static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001135 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001136{
1137 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001138 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001139
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001140 if (trace->multiple_threads) {
1141 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001142 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001143 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001144 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145
1146 return printed;
1147}
1148
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001149static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001150 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001151{
1152 int ret = 0;
1153
1154 switch (event->header.type) {
1155 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001156 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001158 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001159 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001160 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001161 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001162 break;
1163 }
1164
1165 return ret;
1166}
1167
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001168static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001169 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001170 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001171 struct machine *machine)
1172{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001173 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001174 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001175}
1176
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001177static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1178{
1179 struct machine *machine = vmachine;
1180
1181 if (machine->kptr_restrict_warned)
1182 return NULL;
1183
1184 if (symbol_conf.kptr_restrict) {
1185 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1186 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1187 "Kernel samples will not be resolved.\n");
1188 machine->kptr_restrict_warned = true;
1189 return NULL;
1190 }
1191
1192 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1193}
1194
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001195static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1196{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001197 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001198
1199 if (err)
1200 return err;
1201
David Ahern8fb598e2013-09-28 13:13:00 -06001202 trace->host = machine__new_host();
1203 if (trace->host == NULL)
1204 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001205
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001206 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001207 return -errno;
1208
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001209 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001210 evlist->threads, trace__tool_process, false,
1211 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001212 if (err)
1213 symbol__exit();
1214
1215 return err;
1216}
1217
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001218static int syscall__set_arg_fmts(struct syscall *sc)
1219{
1220 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001221 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001222
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001223 sc->arg_fmt = calloc(sc->nr_args, sizeof(*sc->arg_fmt));
1224 if (sc->arg_fmt == NULL)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001225 return -1;
1226
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001227 for (field = sc->args; field; field = field->next, ++idx) {
1228 if (sc->fmt) {
1229 sc->arg_fmt[idx] = sc->fmt->arg[idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001230
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001231 if (sc->fmt->arg[idx].scnprintf)
1232 continue;
1233 }
1234
1235 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001236 (strcmp(field->name, "filename") == 0 ||
1237 strcmp(field->name, "path") == 0 ||
1238 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001239 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001240 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001241 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001242 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001243 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001244 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001245 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001246 else if ((strcmp(field->type, "int") == 0 ||
1247 strcmp(field->type, "unsigned int") == 0 ||
1248 strcmp(field->type, "long") == 0) &&
1249 (len = strlen(field->name)) >= 2 &&
1250 strcmp(field->name + len - 2, "fd") == 0) {
1251 /*
1252 * /sys/kernel/tracing/events/syscalls/sys_enter*
1253 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1254 * 65 int
1255 * 23 unsigned int
1256 * 7 unsigned long
1257 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001258 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001259 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001260 }
1261
1262 return 0;
1263}
1264
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001265static int trace__read_syscall_info(struct trace *trace, int id)
1266{
1267 char tp_name[128];
1268 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001269 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001270
1271 if (name == NULL)
1272 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001273
1274 if (id > trace->syscalls.max) {
1275 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1276
1277 if (nsyscalls == NULL)
1278 return -1;
1279
1280 if (trace->syscalls.max != -1) {
1281 memset(nsyscalls + trace->syscalls.max + 1, 0,
1282 (id - trace->syscalls.max) * sizeof(*sc));
1283 } else {
1284 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1285 }
1286
1287 trace->syscalls.table = nsyscalls;
1288 trace->syscalls.max = id;
1289 }
1290
1291 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001292 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001293
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001294 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001295
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001296 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001297 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001298
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001299 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001300 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001301 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001302 }
1303
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001304 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001305 return -1;
1306
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001307 sc->args = sc->tp_format->format.fields;
1308 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001309 /*
1310 * We need to check and discard the first variable '__syscall_nr'
1311 * or 'nr' that mean the syscall number. It is needless here.
1312 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1313 */
1314 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001315 sc->args = sc->args->next;
1316 --sc->nr_args;
1317 }
1318
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001319 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1320
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001321 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001322}
1323
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001324static int trace__validate_ev_qualifier(struct trace *trace)
1325{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001326 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001327 struct str_node *pos;
1328
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001329 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1330 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1331 sizeof(trace->ev_qualifier_ids.entries[0]));
1332
1333 if (trace->ev_qualifier_ids.entries == NULL) {
1334 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1335 trace->output);
1336 err = -EINVAL;
1337 goto out;
1338 }
1339
1340 i = 0;
1341
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001342 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001343 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001344 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001345
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001346 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001347 if (err == 0) {
1348 fputs("Error:\tInvalid syscall ", trace->output);
1349 err = -EINVAL;
1350 } else {
1351 fputs(", ", trace->output);
1352 }
1353
1354 fputs(sc, trace->output);
1355 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001356
1357 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001358 }
1359
1360 if (err < 0) {
1361 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1362 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001363 zfree(&trace->ev_qualifier_ids.entries);
1364 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001365 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001366out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001367 return err;
1368}
1369
David Ahern55d43bca2015-02-19 15:00:22 -05001370/*
1371 * args is to be interpreted as a series of longs but we need to handle
1372 * 8-byte unaligned accesses. args points to raw_data within the event
1373 * and raw_data is guaranteed to be 8-byte unaligned because it is
1374 * preceded by raw_size which is a u32. So we need to copy args to a temp
1375 * variable to read it. Most notably this avoids extended load instructions
1376 * on unaligned addresses
1377 */
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001378static unsigned long __syscall_arg__val(unsigned char *args, u8 idx)
1379{
1380 unsigned long val;
1381 unsigned char *p = args + sizeof(unsigned long) * idx;
1382
1383 memcpy(&val, p, sizeof(val));
1384 return val;
1385}
1386
1387unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
1388{
1389 return __syscall_arg__val(arg->args, idx);
1390}
David Ahern55d43bca2015-02-19 15:00:22 -05001391
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001392static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001393 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001394 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001395{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001396 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001397 unsigned long val;
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001398 struct thread_trace *ttrace = thread__priv(thread);
1399
1400 /*
1401 * Things like fcntl will set this in its 'cmd' formatter to pick the
1402 * right formatter for the return value (an fd? file flags?), which is
1403 * not needed for syscalls that always return a given type, say an fd.
1404 */
1405 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001406
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001407 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001408 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001409 u8 bit = 1;
1410 struct syscall_arg arg = {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001411 .args = args,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001412 .idx = 0,
1413 .mask = 0,
1414 .trace = trace,
1415 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001416 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001417
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001418 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001419 field = field->next, ++arg.idx, bit <<= 1) {
1420 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001421 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001422
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001423 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001424
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001425 /*
1426 * Suppress this argument if its value is zero and
1427 * and we don't have a string associated in an
1428 * strarray for it.
1429 */
David Ahern55d43bca2015-02-19 15:00:22 -05001430 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001431 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001432 (sc->arg_fmt[arg.idx].show_zero ||
1433 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001434 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1435 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001436 continue;
1437
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001438 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001439 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001440 if (sc->arg_fmt && sc->arg_fmt[arg.idx].scnprintf) {
David Ahern55d43bca2015-02-19 15:00:22 -05001441 arg.val = val;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001442 if (sc->arg_fmt[arg.idx].parm)
1443 arg.parm = sc->arg_fmt[arg.idx].parm;
1444 printed += sc->arg_fmt[arg.idx].scnprintf(bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001445 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001446 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001447 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001448 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001449 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001450 } else if (IS_ERR(sc->tp_format)) {
1451 /*
1452 * If we managed to read the tracepoint /format file, then we
1453 * may end up not having any args, like with gettid(), so only
1454 * print the raw args when we didn't manage to read it.
1455 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001456 int i = 0;
1457
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001458 while (i < 6) {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001459 val = __syscall_arg__val(args, i);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001460 printed += scnprintf(bf + printed, size - printed,
1461 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001462 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001463 ++i;
1464 }
1465 }
1466
1467 return printed;
1468}
1469
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001470typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001471 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001472 struct perf_sample *sample);
1473
1474static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001475 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001476{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001477
1478 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001479
1480 /*
1481 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1482 * before that, leaving at a higher verbosity level till that is
1483 * explained. Reproduced with plain ftrace with:
1484 *
1485 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1486 * grep "NR -1 " /t/trace_pipe
1487 *
1488 * After generating some load on the machine.
1489 */
1490 if (verbose > 1) {
1491 static u64 n;
1492 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1493 id, perf_evsel__name(evsel), ++n);
1494 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001495 return NULL;
1496 }
1497
1498 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1499 trace__read_syscall_info(trace, id))
1500 goto out_cant_read;
1501
1502 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1503 goto out_cant_read;
1504
1505 return &trace->syscalls.table[id];
1506
1507out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001508 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001509 fprintf(trace->output, "Problems reading syscall %d", id);
1510 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1511 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1512 fputs(" information\n", trace->output);
1513 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001514 return NULL;
1515}
1516
David Ahernbf2575c2013-10-08 21:26:53 -06001517static void thread__update_stats(struct thread_trace *ttrace,
1518 int id, struct perf_sample *sample)
1519{
1520 struct int_node *inode;
1521 struct stats *stats;
1522 u64 duration = 0;
1523
1524 inode = intlist__findnew(ttrace->syscall_stats, id);
1525 if (inode == NULL)
1526 return;
1527
1528 stats = inode->priv;
1529 if (stats == NULL) {
1530 stats = malloc(sizeof(struct stats));
1531 if (stats == NULL)
1532 return;
1533 init_stats(stats);
1534 inode->priv = stats;
1535 }
1536
1537 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1538 duration = sample->time - ttrace->entry_time;
1539
1540 update_stats(stats, duration);
1541}
1542
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001543static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1544{
1545 struct thread_trace *ttrace;
1546 u64 duration;
1547 size_t printed;
1548
1549 if (trace->current == NULL)
1550 return 0;
1551
1552 ttrace = thread__priv(trace->current);
1553
1554 if (!ttrace->entry_pending)
1555 return 0;
1556
1557 duration = sample->time - ttrace->entry_time;
1558
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001559 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001560 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1561 ttrace->entry_pending = false;
1562
1563 return printed;
1564}
1565
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001566static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001567 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001568 struct perf_sample *sample)
1569{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001570 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001571 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001572 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001573 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001574 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001575 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001576 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001577
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001578 if (sc == NULL)
1579 return -1;
1580
David Ahern8fb598e2013-09-28 13:13:00 -06001581 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001582 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001583 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001584 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001585
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001586 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001587
1588 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001589 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001590 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001591 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001592 }
1593
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001594 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001595 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001596
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001597 ttrace->entry_time = sample->time;
1598 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001599 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001600
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001601 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001602 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001603
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001604 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001605 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001606 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001607 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001608 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001609 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001610 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001611 /* See trace__vfs_getname & trace__sys_exit */
1612 ttrace->filename.pending_open = false;
1613 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001614
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001615 if (trace->current != thread) {
1616 thread__put(trace->current);
1617 trace->current = thread__get(thread);
1618 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001619 err = 0;
1620out_put:
1621 thread__put(thread);
1622 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001623}
1624
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001625static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1626 struct perf_sample *sample,
1627 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001628{
1629 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001630
1631 if (machine__resolve(trace->host, &al, sample) < 0 ||
1632 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1633 return -1;
1634
1635 return 0;
1636}
1637
1638static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1639{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001640 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001641 const unsigned int print_opts = EVSEL__PRINT_SYM |
1642 EVSEL__PRINT_DSO |
1643 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001644
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001645 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001646}
1647
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001648static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001649 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001650 struct perf_sample *sample)
1651{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001652 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001653 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001654 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001655 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001656 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001657 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001658 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001659
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001660 if (sc == NULL)
1661 return -1;
1662
David Ahern8fb598e2013-09-28 13:13:00 -06001663 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001665 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001666 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001667
David Ahernbf2575c2013-10-08 21:26:53 -06001668 if (trace->summary)
1669 thread__update_stats(ttrace, id, sample);
1670
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001671 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001672
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001673 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001674 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1675 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001676 ++trace->stats.vfs_getname;
1677 }
1678
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001679 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001680 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001681 if (trace__filter_duration(trace, duration))
1682 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001683 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001684 } else if (trace->duration_filter)
1685 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001686
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001687 if (sample->callchain) {
1688 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1689 if (callchain_ret == 0) {
1690 if (callchain_cursor.nr < trace->min_stack)
1691 goto out;
1692 callchain_ret = 1;
1693 }
1694 }
1695
David Ahernfd2eaba2013-11-12 09:31:15 -07001696 if (trace->summary_only)
1697 goto out;
1698
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001699 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001700
1701 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001702 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001703 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001704 fprintf(trace->output, " ... [");
1705 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1706 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001707 }
1708
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001709 if (sc->fmt == NULL) {
1710signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001711 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001712 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001713 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001714 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001715 *e = audit_errno_to_name(-ret);
1716
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001717 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001718 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001720 else if (ttrace->ret_scnprintf) {
1721 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001722 struct syscall_arg arg = {
1723 .val = ret,
1724 .thread = thread,
1725 .trace = trace,
1726 };
1727 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001728 ttrace->ret_scnprintf = NULL;
1729 fprintf(trace->output, ") = %s", bf);
1730 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001731 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001732 else if (sc->fmt->errpid) {
1733 struct thread *child = machine__find_thread(trace->host, ret, ret);
1734
1735 if (child != NULL) {
1736 fprintf(trace->output, ") = %ld", ret);
1737 if (child->comm_set)
1738 fprintf(trace->output, " (%s)", thread__comm_str(child));
1739 thread__put(child);
1740 }
1741 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001742 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001743
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001744 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001745
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001746 if (callchain_ret > 0)
1747 trace__fprintf_callchain(trace, sample);
1748 else if (callchain_ret < 0)
1749 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001750out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001751 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001752 err = 0;
1753out_put:
1754 thread__put(thread);
1755 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001756}
1757
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001758static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001759 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001760 struct perf_sample *sample)
1761{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001762 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1763 struct thread_trace *ttrace;
1764 size_t filename_len, entry_str_len, to_move;
1765 ssize_t remaining_space;
1766 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001767 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001768
1769 if (!thread)
1770 goto out;
1771
1772 ttrace = thread__priv(thread);
1773 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001774 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001775
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001776 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001777 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001778 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001779
1780 if (ttrace->filename.namelen < filename_len) {
1781 char *f = realloc(ttrace->filename.name, filename_len + 1);
1782
1783 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001784 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001785
1786 ttrace->filename.namelen = filename_len;
1787 ttrace->filename.name = f;
1788 }
1789
1790 strcpy(ttrace->filename.name, filename);
1791 ttrace->filename.pending_open = true;
1792
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001793 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001794 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001795
1796 entry_str_len = strlen(ttrace->entry_str);
1797 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1798 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001799 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001800
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001801 if (filename_len > (size_t)remaining_space) {
1802 filename += filename_len - remaining_space;
1803 filename_len = remaining_space;
1804 }
1805
1806 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1807 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1808 memmove(pos + filename_len, pos, to_move);
1809 memcpy(pos, filename, filename_len);
1810
1811 ttrace->filename.ptr = 0;
1812 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001813out_put:
1814 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001815out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001816 return 0;
1817}
1818
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001819static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001820 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001821 struct perf_sample *sample)
1822{
1823 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1824 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001825 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001826 sample->pid,
1827 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001828 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001829
1830 if (ttrace == NULL)
1831 goto out_dump;
1832
1833 ttrace->runtime_ms += runtime_ms;
1834 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001835out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001836 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001837 return 0;
1838
1839out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001840 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001841 evsel->name,
1842 perf_evsel__strval(evsel, sample, "comm"),
1843 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1844 runtime,
1845 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001846 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001847}
1848
Wang Nan1d6c9402016-02-26 09:31:55 +00001849static void bpf_output__printer(enum binary_printer_ops op,
1850 unsigned int val, void *extra)
1851{
1852 FILE *output = extra;
1853 unsigned char ch = (unsigned char)val;
1854
1855 switch (op) {
1856 case BINARY_PRINT_CHAR_DATA:
1857 fprintf(output, "%c", isprint(ch) ? ch : '.');
1858 break;
1859 case BINARY_PRINT_DATA_BEGIN:
1860 case BINARY_PRINT_LINE_BEGIN:
1861 case BINARY_PRINT_ADDR:
1862 case BINARY_PRINT_NUM_DATA:
1863 case BINARY_PRINT_NUM_PAD:
1864 case BINARY_PRINT_SEP:
1865 case BINARY_PRINT_CHAR_PAD:
1866 case BINARY_PRINT_LINE_END:
1867 case BINARY_PRINT_DATA_END:
1868 default:
1869 break;
1870 }
1871}
1872
1873static void bpf_output__fprintf(struct trace *trace,
1874 struct perf_sample *sample)
1875{
1876 print_binary(sample->raw_data, sample->raw_size, 8,
1877 bpf_output__printer, trace->output);
1878}
1879
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001880static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1881 union perf_event *event __maybe_unused,
1882 struct perf_sample *sample)
1883{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001884 int callchain_ret = 0;
1885
1886 if (sample->callchain) {
1887 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1888 if (callchain_ret == 0) {
1889 if (callchain_cursor.nr < trace->min_stack)
1890 goto out;
1891 callchain_ret = 1;
1892 }
1893 }
1894
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001895 trace__printf_interrupted_entry(trace, sample);
1896 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001897
1898 if (trace->trace_syscalls)
1899 fprintf(trace->output, "( ): ");
1900
1901 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001902
Wang Nan1d6c9402016-02-26 09:31:55 +00001903 if (perf_evsel__is_bpf_output(evsel)) {
1904 bpf_output__fprintf(trace, sample);
1905 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001906 event_format__fprintf(evsel->tp_format, sample->cpu,
1907 sample->raw_data, sample->raw_size,
1908 trace->output);
1909 }
1910
1911 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001912
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001913 if (callchain_ret > 0)
1914 trace__fprintf_callchain(trace, sample);
1915 else if (callchain_ret < 0)
1916 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1917out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001918 return 0;
1919}
1920
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001921static void print_location(FILE *f, struct perf_sample *sample,
1922 struct addr_location *al,
1923 bool print_dso, bool print_sym)
1924{
1925
Namhyung Kimbb963e12017-02-17 17:17:38 +09001926 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001927 fprintf(f, "%s@", al->map->dso->long_name);
1928
Namhyung Kimbb963e12017-02-17 17:17:38 +09001929 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001930 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001931 al->addr - al->sym->start);
1932 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001933 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001934 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001935 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001936}
1937
1938static int trace__pgfault(struct trace *trace,
1939 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001940 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001941 struct perf_sample *sample)
1942{
1943 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001944 struct addr_location al;
1945 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001946 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001947 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001948 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001949
1950 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001951
1952 if (sample->callchain) {
1953 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1954 if (callchain_ret == 0) {
1955 if (callchain_cursor.nr < trace->min_stack)
1956 goto out_put;
1957 callchain_ret = 1;
1958 }
1959 }
1960
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001961 ttrace = thread__trace(thread, trace->output);
1962 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001963 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001964
1965 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1966 ttrace->pfmaj++;
1967 else
1968 ttrace->pfmin++;
1969
1970 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001971 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001972
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001973 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001974 sample->ip, &al);
1975
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001976 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001977
1978 fprintf(trace->output, "%sfault [",
1979 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1980 "maj" : "min");
1981
1982 print_location(trace->output, sample, &al, false, true);
1983
1984 fprintf(trace->output, "] => ");
1985
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001986 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001987 sample->addr, &al);
1988
1989 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001990 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001991 MAP__FUNCTION, sample->addr, &al);
1992
1993 if (al.map)
1994 map_type = 'x';
1995 else
1996 map_type = '?';
1997 }
1998
1999 print_location(trace->output, sample, &al, true, false);
2000
2001 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002002
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002003 if (callchain_ret > 0)
2004 trace__fprintf_callchain(trace, sample);
2005 else if (callchain_ret < 0)
2006 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002007out:
2008 err = 0;
2009out_put:
2010 thread__put(thread);
2011 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002012}
2013
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002014static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002015 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002016 struct perf_sample *sample)
2017{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002018 /*
2019 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2020 * and don't use sample->time unconditionally, we may end up having
2021 * some other event in the future without PERF_SAMPLE_TIME for good
2022 * reason, i.e. we may not be interested in its timestamps, just in
2023 * it taking place, picking some piece of information when it
2024 * appears in our event stream (vfs_getname comes to mind).
2025 */
2026 if (trace->base_time == 0 && !trace->full_time &&
2027 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002028 trace->base_time = sample->time;
2029}
2030
David Ahern6810fc92013-08-28 22:29:52 -06002031static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002032 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002033 struct perf_sample *sample,
2034 struct perf_evsel *evsel,
2035 struct machine *machine __maybe_unused)
2036{
2037 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002038 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002039 int err = 0;
2040
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002041 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002042
David Ahernaa07df62016-11-25 09:29:52 -07002043 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2044 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002045 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002046
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002047 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002048
David Ahern31605652013-12-04 19:41:41 -07002049 if (handler) {
2050 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002051 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002052 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002053out:
2054 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002055 return err;
2056}
2057
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002058static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002059{
2060 unsigned int rec_argc, i, j;
2061 const char **rec_argv;
2062 const char * const record_args[] = {
2063 "record",
2064 "-R",
2065 "-m", "1024",
2066 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002067 };
2068
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002069 const char * const sc_args[] = { "-e", };
2070 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2071 const char * const majpf_args[] = { "-e", "major-faults" };
2072 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2073 const char * const minpf_args[] = { "-e", "minor-faults" };
2074 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2075
David Ahern9aca7f12013-12-04 19:41:39 -07002076 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002077 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2078 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002079 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2080
2081 if (rec_argv == NULL)
2082 return -ENOMEM;
2083
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002084 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002085 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002086 rec_argv[j++] = record_args[i];
2087
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002088 if (trace->trace_syscalls) {
2089 for (i = 0; i < sc_args_nr; i++)
2090 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002091
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002092 /* event string may be different for older kernels - e.g., RHEL6 */
2093 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2094 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2095 else if (is_valid_tracepoint("syscalls:sys_enter"))
2096 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2097 else {
2098 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2099 return -1;
2100 }
David Ahern9aca7f12013-12-04 19:41:39 -07002101 }
David Ahern9aca7f12013-12-04 19:41:39 -07002102
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002103 if (trace->trace_pgfaults & TRACE_PFMAJ)
2104 for (i = 0; i < majpf_args_nr; i++)
2105 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002106
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002107 if (trace->trace_pgfaults & TRACE_PFMIN)
2108 for (i = 0; i < minpf_args_nr; i++)
2109 rec_argv[j++] = minpf_args[i];
2110
2111 for (i = 0; i < (unsigned int)argc; i++)
2112 rec_argv[j++] = argv[i];
2113
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002114 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002115}
2116
David Ahernbf2575c2013-10-08 21:26:53 -06002117static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2118
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002119static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002120{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002121 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002122
2123 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002124 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002125
2126 if (perf_evsel__field(evsel, "pathname") == NULL) {
2127 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002128 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002129 }
2130
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002131 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002132 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002133 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002134}
2135
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002136static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002137{
2138 struct perf_evsel *evsel;
2139 struct perf_event_attr attr = {
2140 .type = PERF_TYPE_SOFTWARE,
2141 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002142 };
2143
2144 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002145 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002146
2147 event_attr_init(&attr);
2148
2149 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002150 if (evsel)
2151 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002152
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002153 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002154}
2155
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002156static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2157{
2158 const u32 type = event->header.type;
2159 struct perf_evsel *evsel;
2160
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002161 if (type != PERF_RECORD_SAMPLE) {
2162 trace__process_event(trace, trace->host, event, sample);
2163 return;
2164 }
2165
2166 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2167 if (evsel == NULL) {
2168 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2169 return;
2170 }
2171
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002172 trace__set_base_time(trace, evsel, sample);
2173
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002174 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2175 sample->raw_data == NULL) {
2176 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2177 perf_evsel__name(evsel), sample->tid,
2178 sample->cpu, sample->raw_size);
2179 } else {
2180 tracepoint_handler handler = evsel->handler;
2181 handler(trace, evsel, event, sample);
2182 }
2183}
2184
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002185static int trace__add_syscall_newtp(struct trace *trace)
2186{
2187 int ret = -1;
2188 struct perf_evlist *evlist = trace->evlist;
2189 struct perf_evsel *sys_enter, *sys_exit;
2190
2191 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2192 if (sys_enter == NULL)
2193 goto out;
2194
2195 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2196 goto out_delete_sys_enter;
2197
2198 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2199 if (sys_exit == NULL)
2200 goto out_delete_sys_enter;
2201
2202 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2203 goto out_delete_sys_exit;
2204
2205 perf_evlist__add(evlist, sys_enter);
2206 perf_evlist__add(evlist, sys_exit);
2207
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002208 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002209 /*
2210 * We're interested only in the user space callchain
2211 * leading to the syscall, allow overriding that for
2212 * debugging reasons using --kernel_syscall_callchains
2213 */
2214 sys_exit->attr.exclude_callchain_kernel = 1;
2215 }
2216
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002217 trace->syscalls.events.sys_enter = sys_enter;
2218 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002219
2220 ret = 0;
2221out:
2222 return ret;
2223
2224out_delete_sys_exit:
2225 perf_evsel__delete_priv(sys_exit);
2226out_delete_sys_enter:
2227 perf_evsel__delete_priv(sys_enter);
2228 goto out;
2229}
2230
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002231static int trace__set_ev_qualifier_filter(struct trace *trace)
2232{
2233 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002234 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002235 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2236 trace->ev_qualifier_ids.nr,
2237 trace->ev_qualifier_ids.entries);
2238
2239 if (filter == NULL)
2240 goto out_enomem;
2241
Mathieu Poirier3541c032016-09-16 08:44:04 -06002242 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2243 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002244 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002245 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002246 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002247
2248 free(filter);
2249out:
2250 return err;
2251out_enomem:
2252 errno = ENOMEM;
2253 goto out;
2254}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002255
Namhyung Kimf15eb532012-10-05 14:02:16 +09002256static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002257{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002258 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002259 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002260 int err = -1, i;
2261 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002262 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002263 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002264
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002265 trace->live = true;
2266
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002267 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002268 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002269
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002270 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002271 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002272
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002273 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2274 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2275 if (pgfault_maj == NULL)
2276 goto out_error_mem;
2277 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002278 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002279
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002280 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2281 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2282 if (pgfault_min == NULL)
2283 goto out_error_mem;
2284 perf_evlist__add(evlist, pgfault_min);
2285 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002286
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002287 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002288 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2289 trace__sched_stat_runtime))
2290 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002291
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002292 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2293 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002294 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002295 goto out_delete_evlist;
2296 }
2297
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002298 err = trace__symbols_init(trace, evlist);
2299 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002300 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002301 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002302 }
2303
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002304 perf_evlist__config(evlist, &trace->opts, NULL);
2305
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002306 if (callchain_param.enabled) {
2307 bool use_identifier = false;
2308
2309 if (trace->syscalls.events.sys_exit) {
2310 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2311 &trace->opts, &callchain_param);
2312 use_identifier = true;
2313 }
2314
2315 if (pgfault_maj) {
2316 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2317 use_identifier = true;
2318 }
2319
2320 if (pgfault_min) {
2321 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2322 use_identifier = true;
2323 }
2324
2325 if (use_identifier) {
2326 /*
2327 * Now we have evsels with different sample_ids, use
2328 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2329 * from a fixed position in each ring buffer record.
2330 *
2331 * As of this the changeset introducing this comment, this
2332 * isn't strictly needed, as the fields that can come before
2333 * PERF_SAMPLE_ID are all used, but we'll probably disable
2334 * some of those for things like copying the payload of
2335 * pointer syscall arguments, and for vfs_getname we don't
2336 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2337 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2338 */
2339 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2340 perf_evlist__reset_sample_bit(evlist, ID);
2341 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002342 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002343
Namhyung Kimf15eb532012-10-05 14:02:16 +09002344 signal(SIGCHLD, sig_handler);
2345 signal(SIGINT, sig_handler);
2346
2347 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002348 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002349 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002350 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002351 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002352 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002353 }
2354 }
2355
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002356 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002357 if (err < 0)
2358 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002359
Wang Nanba504232016-02-26 09:31:54 +00002360 err = bpf__apply_obj_config();
2361 if (err) {
2362 char errbuf[BUFSIZ];
2363
2364 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2365 pr_err("ERROR: Apply config to BPF failed: %s\n",
2366 errbuf);
2367 goto out_error_open;
2368 }
2369
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002370 /*
2371 * Better not use !target__has_task() here because we need to cover the
2372 * case where no threads were specified in the command line, but a
2373 * workload was, and in that case we will fill in the thread_map when
2374 * we fork the workload in perf_evlist__prepare_workload.
2375 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002376 if (trace->filter_pids.nr > 0)
2377 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002378 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002379 err = perf_evlist__set_filter_pid(evlist, getpid());
2380
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002381 if (err < 0)
2382 goto out_error_mem;
2383
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002384 if (trace->ev_qualifier_ids.nr > 0) {
2385 err = trace__set_ev_qualifier_filter(trace);
2386 if (err < 0)
2387 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002388
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002389 pr_debug("event qualifier tracepoint filter: %s\n",
2390 trace->syscalls.events.sys_exit->filter);
2391 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002392
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002393 err = perf_evlist__apply_filters(evlist, &evsel);
2394 if (err < 0)
2395 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002396
Jiri Olsaf8850372013-11-28 17:57:22 +01002397 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002398 if (err < 0)
2399 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002400
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002401 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002402 perf_evlist__enable(evlist);
2403
Namhyung Kimf15eb532012-10-05 14:02:16 +09002404 if (forks)
2405 perf_evlist__start_workload(evlist);
2406
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002407 if (trace->opts.initial_delay) {
2408 usleep(trace->opts.initial_delay * 1000);
2409 perf_evlist__enable(evlist);
2410 }
2411
Jiri Olsae13798c2015-06-23 00:36:02 +02002412 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002413 evlist->threads->nr > 1 ||
2414 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002415again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002416 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002417
2418 for (i = 0; i < evlist->nr_mmaps; i++) {
2419 union perf_event *event;
2420
2421 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002422 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002423
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002424 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002425
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002426 err = perf_evlist__parse_sample(evlist, event, &sample);
2427 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002428 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002429 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002430 }
2431
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002432 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002433next_event:
2434 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002435
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002436 if (interrupted)
2437 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002438
2439 if (done && !draining) {
2440 perf_evlist__disable(evlist);
2441 draining = true;
2442 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002443 }
2444 }
2445
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002446 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002447 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002448
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002449 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2450 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2451 draining = true;
2452
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002453 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002454 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002455 } else {
2456 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002457 }
2458
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002459out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002460 thread__zput(trace->current);
2461
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002462 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002463
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002464 if (!err) {
2465 if (trace->summary)
2466 trace__fprintf_thread_summary(trace, trace->output);
2467
2468 if (trace->show_tool_stats) {
2469 fprintf(trace->output, "Stats:\n "
2470 " vfs_getname : %" PRIu64 "\n"
2471 " proc_getname: %" PRIu64 "\n",
2472 trace->stats.vfs_getname,
2473 trace->stats.proc_getname);
2474 }
2475 }
David Ahernbf2575c2013-10-08 21:26:53 -06002476
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477out_delete_evlist:
2478 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002479 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002480 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002481 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002482{
2483 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002484
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002485out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002486 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002487 goto out_error;
2488
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002489out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002490 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002491 goto out_error;
2492
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002493out_error_mmap:
2494 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2495 goto out_error;
2496
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002497out_error_open:
2498 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2499
2500out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002501 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302502 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002503
2504out_error_apply_filters:
2505 fprintf(trace->output,
2506 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2507 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002508 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002509 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002510}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002511out_error_mem:
2512 fprintf(trace->output, "Not enough memory to run!\n");
2513 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002514
2515out_errno:
2516 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2517 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002518}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002519
David Ahern6810fc92013-08-28 22:29:52 -06002520static int trace__replay(struct trace *trace)
2521{
2522 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002523 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002524 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002525 struct perf_data_file file = {
2526 .path = input_name,
2527 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002528 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002529 };
David Ahern6810fc92013-08-28 22:29:52 -06002530 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002531 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002532 int err = -1;
2533
2534 trace->tool.sample = trace__process_sample;
2535 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002536 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002537 trace->tool.comm = perf_event__process_comm;
2538 trace->tool.exit = perf_event__process_exit;
2539 trace->tool.fork = perf_event__process_fork;
2540 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302541 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002542 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302543 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002544
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002545 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002546 trace->tool.ordering_requires_timestamps = true;
2547
2548 /* add tid to output */
2549 trace->multiple_threads = true;
2550
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002551 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002552 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002553 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002554
David Ahernaa07df62016-11-25 09:29:52 -07002555 if (trace->opts.target.pid)
2556 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2557
2558 if (trace->opts.target.tid)
2559 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2560
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002561 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002562 goto out;
2563
David Ahern8fb598e2013-09-28 13:13:00 -06002564 trace->host = &session->machines.host;
2565
David Ahern6810fc92013-08-28 22:29:52 -06002566 err = perf_session__set_tracepoints_handlers(session, handlers);
2567 if (err)
2568 goto out;
2569
Namhyung Kim003824e2013-11-12 15:25:00 +09002570 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2571 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002572 /* older kernels have syscalls tp versus raw_syscalls */
2573 if (evsel == NULL)
2574 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2575 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002576
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002577 if (evsel &&
2578 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2579 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002580 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2581 goto out;
2582 }
2583
2584 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2585 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002586 if (evsel == NULL)
2587 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2588 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002589 if (evsel &&
2590 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2591 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002592 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002593 goto out;
2594 }
2595
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002596 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002597 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2598 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2599 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2600 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2601 evsel->handler = trace__pgfault;
2602 }
2603
David Ahern6810fc92013-08-28 22:29:52 -06002604 setup_pager();
2605
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002606 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002607 if (err)
2608 pr_err("Failed to process events, error %d", err);
2609
David Ahernbf2575c2013-10-08 21:26:53 -06002610 else if (trace->summary)
2611 trace__fprintf_thread_summary(trace, trace->output);
2612
David Ahern6810fc92013-08-28 22:29:52 -06002613out:
2614 perf_session__delete(session);
2615
2616 return err;
2617}
2618
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002619static size_t trace__fprintf_threads_header(FILE *fp)
2620{
2621 size_t printed;
2622
Pekka Enberg99ff7152013-11-12 16:42:14 +02002623 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002624
2625 return printed;
2626}
2627
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002628DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2629 struct stats *stats;
2630 double msecs;
2631 int syscall;
2632)
2633{
2634 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2635 struct stats *stats = source->priv;
2636
2637 entry->syscall = source->i;
2638 entry->stats = stats;
2639 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2640}
2641
David Ahernbf2575c2013-10-08 21:26:53 -06002642static size_t thread__dump_stats(struct thread_trace *ttrace,
2643 struct trace *trace, FILE *fp)
2644{
David Ahernbf2575c2013-10-08 21:26:53 -06002645 size_t printed = 0;
2646 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002647 struct rb_node *nd;
2648 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002649
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002650 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002651 return 0;
2652
2653 printed += fprintf(fp, "\n");
2654
Milian Wolff834fd462015-08-06 11:24:29 +02002655 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2656 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2657 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002658
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002659 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002660 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002661 if (stats) {
2662 double min = (double)(stats->min) / NSEC_PER_MSEC;
2663 double max = (double)(stats->max) / NSEC_PER_MSEC;
2664 double avg = avg_stats(stats);
2665 double pct;
2666 u64 n = (u64) stats->n;
2667
2668 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2669 avg /= NSEC_PER_MSEC;
2670
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002671 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002672 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002673 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002674 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002675 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002676 }
David Ahernbf2575c2013-10-08 21:26:53 -06002677 }
2678
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002679 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002680 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002681
2682 return printed;
2683}
2684
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002685static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002686{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002687 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002688 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002689 double ratio;
2690
2691 if (ttrace == NULL)
2692 return 0;
2693
2694 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2695
Pekka Enberg15e65c62013-11-14 18:43:30 +02002696 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002697 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002698 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002699 if (ttrace->pfmaj)
2700 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2701 if (ttrace->pfmin)
2702 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002703 if (trace->sched)
2704 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2705 else if (fputc('\n', fp) != EOF)
2706 ++printed;
2707
David Ahernbf2575c2013-10-08 21:26:53 -06002708 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002709
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002710 return printed;
2711}
David Ahern896cbb52013-09-28 13:12:59 -06002712
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002713static unsigned long thread__nr_events(struct thread_trace *ttrace)
2714{
2715 return ttrace ? ttrace->nr_events : 0;
2716}
2717
2718DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2719 struct thread *thread;
2720)
2721{
2722 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002723}
2724
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002725static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2726{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002727 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2728 size_t printed = trace__fprintf_threads_header(fp);
2729 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002730
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002731 if (threads == NULL) {
2732 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2733 return 0;
2734 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002735
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002736 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002737 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2738
2739 resort_rb__delete(threads);
2740
2741 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002742}
2743
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002744static int trace__set_duration(const struct option *opt, const char *str,
2745 int unset __maybe_unused)
2746{
2747 struct trace *trace = opt->value;
2748
2749 trace->duration_filter = atof(str);
2750 return 0;
2751}
2752
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002753static int trace__set_filter_pids(const struct option *opt, const char *str,
2754 int unset __maybe_unused)
2755{
2756 int ret = -1;
2757 size_t i;
2758 struct trace *trace = opt->value;
2759 /*
2760 * FIXME: introduce a intarray class, plain parse csv and create a
2761 * { int nr, int entries[] } struct...
2762 */
2763 struct intlist *list = intlist__new(str);
2764
2765 if (list == NULL)
2766 return -1;
2767
2768 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2769 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2770
2771 if (trace->filter_pids.entries == NULL)
2772 goto out;
2773
2774 trace->filter_pids.entries[0] = getpid();
2775
2776 for (i = 1; i < trace->filter_pids.nr; ++i)
2777 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2778
2779 intlist__delete(list);
2780 ret = 0;
2781out:
2782 return ret;
2783}
2784
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002785static int trace__open_output(struct trace *trace, const char *filename)
2786{
2787 struct stat st;
2788
2789 if (!stat(filename, &st) && st.st_size) {
2790 char oldname[PATH_MAX];
2791
2792 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2793 unlink(oldname);
2794 rename(filename, oldname);
2795 }
2796
2797 trace->output = fopen(filename, "w");
2798
2799 return trace->output == NULL ? -errno : 0;
2800}
2801
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002802static int parse_pagefaults(const struct option *opt, const char *str,
2803 int unset __maybe_unused)
2804{
2805 int *trace_pgfaults = opt->value;
2806
2807 if (strcmp(str, "all") == 0)
2808 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2809 else if (strcmp(str, "maj") == 0)
2810 *trace_pgfaults |= TRACE_PFMAJ;
2811 else if (strcmp(str, "min") == 0)
2812 *trace_pgfaults |= TRACE_PFMIN;
2813 else
2814 return -1;
2815
2816 return 0;
2817}
2818
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002819static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2820{
2821 struct perf_evsel *evsel;
2822
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002823 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002824 evsel->handler = handler;
2825}
2826
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002827/*
2828 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2829 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2830 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2831 *
2832 * It'd be better to introduce a parse_options() variant that would return a
2833 * list with the terms it didn't match to an event...
2834 */
2835static int trace__parse_events_option(const struct option *opt, const char *str,
2836 int unset __maybe_unused)
2837{
2838 struct trace *trace = (struct trace *)opt->value;
2839 const char *s = str;
2840 char *sep = NULL, *lists[2] = { NULL, NULL, };
2841 int len = strlen(str), err = -1, list;
2842 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2843 char group_name[PATH_MAX];
2844
2845 if (strace_groups_dir == NULL)
2846 return -1;
2847
2848 if (*s == '!') {
2849 ++s;
2850 trace->not_ev_qualifier = true;
2851 }
2852
2853 while (1) {
2854 if ((sep = strchr(s, ',')) != NULL)
2855 *sep = '\0';
2856
2857 list = 0;
2858 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2859 list = 1;
2860 } else {
2861 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2862 if (access(group_name, R_OK) == 0)
2863 list = 1;
2864 }
2865
2866 if (lists[list]) {
2867 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2868 } else {
2869 lists[list] = malloc(len);
2870 if (lists[list] == NULL)
2871 goto out;
2872 strcpy(lists[list], s);
2873 }
2874
2875 if (!sep)
2876 break;
2877
2878 *sep = ',';
2879 s = sep + 1;
2880 }
2881
2882 if (lists[1] != NULL) {
2883 struct strlist_config slist_config = {
2884 .dirname = strace_groups_dir,
2885 };
2886
2887 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2888 if (trace->ev_qualifier == NULL) {
2889 fputs("Not enough memory to parse event qualifier", trace->output);
2890 goto out;
2891 }
2892
2893 if (trace__validate_ev_qualifier(trace))
2894 goto out;
2895 }
2896
2897 err = 0;
2898
2899 if (lists[0]) {
2900 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2901 "event selector. use 'perf list' to list available events",
2902 parse_events_option);
2903 err = parse_events_option(&o, lists[0], 0);
2904 }
2905out:
2906 if (sep)
2907 *sep = ',';
2908
2909 return err;
2910}
2911
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002912int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002913{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002914 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002915 "perf trace [<options>] [<command>]",
2916 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002917 "perf trace record [<options>] [<command>]",
2918 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002919 NULL
2920 };
2921 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002922 .syscalls = {
2923 . max = -1,
2924 },
2925 .opts = {
2926 .target = {
2927 .uid = UINT_MAX,
2928 .uses_mmap = true,
2929 },
2930 .user_freq = UINT_MAX,
2931 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002932 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002933 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002934 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002935 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002936 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002937 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002938 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002939 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002940 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002941 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002942 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002943 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002944 OPT_CALLBACK('e', "event", &trace, "event",
2945 "event/syscall selector. use 'perf list' to list available events",
2946 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002947 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2948 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002949 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002950 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2951 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002952 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002953 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002954 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2955 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002956 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002957 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002958 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2959 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002960 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002961 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002962 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002963 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002964 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002965 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002966 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2967 "number of mmap data pages",
2968 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002969 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002970 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002971 OPT_CALLBACK(0, "duration", &trace, "float",
2972 "show only events with duration > N.M ms",
2973 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002974 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002975 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002976 OPT_BOOLEAN('T', "time", &trace.full_time,
2977 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002978 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2979 "Show only syscall summary with statistics"),
2980 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2981 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002982 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2983 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002984 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002985 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002986 OPT_CALLBACK(0, "call-graph", &trace.opts,
2987 "record_mode[,record_size]", record_callchain_help,
2988 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002989 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2990 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002991 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2992 "Set the minimum stack depth when parsing the callchain, "
2993 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002994 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2995 "Set the maximum stack depth when parsing the callchain, "
2996 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002997 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002998 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2999 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003000 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3001 "ms to wait before starting measurement after program "
3002 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003003 OPT_END()
3004 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003005 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003006 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003007 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003008 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003009 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003010
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003011 signal(SIGSEGV, sighandler_dump_stack);
3012 signal(SIGFPE, sighandler_dump_stack);
3013
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003014 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003015 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003016
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003017 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003018 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003019 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003020 goto out;
3021 }
3022
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003023 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3024 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003025
Wang Nand7888572016-04-08 15:07:24 +00003026 err = bpf__setup_stdout(trace.evlist);
3027 if (err) {
3028 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3029 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3030 goto out;
3031 }
3032
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003033 err = -1;
3034
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003035 if (trace.trace_pgfaults) {
3036 trace.opts.sample_address = true;
3037 trace.opts.sample_time = true;
3038 }
3039
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003040 if (trace.opts.mmap_pages == UINT_MAX)
3041 mmap_pages_user_set = false;
3042
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003043 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003044 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003045 max_stack_user_set = false;
3046 }
3047
3048#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003049 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003050 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3051#endif
3052
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003053 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003054 if (!mmap_pages_user_set && geteuid() == 0)
3055 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3056
Milian Wolff566a0882016-04-08 13:34:15 +02003057 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003058 }
Milian Wolff566a0882016-04-08 13:34:15 +02003059
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003060 if (trace.evlist->nr_entries > 0)
3061 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3062
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003063 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3064 return trace__record(&trace, argc-1, &argv[1]);
3065
3066 /* summary_only implies summary option, but don't overwrite summary if set */
3067 if (trace.summary_only)
3068 trace.summary = trace.summary_only;
3069
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003070 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3071 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003072 pr_err("Please specify something to trace.\n");
3073 return -1;
3074 }
3075
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003076 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003077 pr_err("The -e option can't be used with --no-syscalls.\n");
3078 goto out;
3079 }
3080
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003081 if (output_name != NULL) {
3082 err = trace__open_output(&trace, output_name);
3083 if (err < 0) {
3084 perror("failed to create output file");
3085 goto out;
3086 }
3087 }
3088
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003089 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3090
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003091 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003092 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003093 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003094 fprintf(trace.output, "%s", bf);
3095 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003096 }
3097
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003098 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003099 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003100 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003101 fprintf(trace.output, "%s", bf);
3102 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003103 }
3104
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003105 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003106 trace.opts.target.system_wide = true;
3107
David Ahern6810fc92013-08-28 22:29:52 -06003108 if (input_name)
3109 err = trace__replay(&trace);
3110 else
3111 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003112
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003113out_close:
3114 if (output_name != NULL)
3115 fclose(trace.output);
3116out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003117 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003118}