blob: fc4d33a6aa58a5effb4826a1c89168ba5b40e898 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030024#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030025#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060026#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030027#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030028#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060029#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030030#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060031#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030032#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060033#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030034#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060035#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030036#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010037#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070038#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000039#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020040#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030041#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030042#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030043#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030044#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030045
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030046#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030047#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030048#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030049#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030050#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030052#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020053#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030054#include <linux/filter.h>
55#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030060
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030061#include "sane_ctype.h"
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef O_CLOEXEC
64# define O_CLOEXEC 02000000
65#endif
66
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030067#ifndef F_LINUX_SPECIFIC_BASE
68# define F_LINUX_SPECIFIC_BASE 1024
69#endif
70
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030071struct trace {
72 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030073 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030074 struct {
75 int max;
76 struct syscall *table;
77 struct {
78 struct perf_evsel *sys_enter,
79 *sys_exit;
80 } events;
81 } syscalls;
82 struct record_opts opts;
83 struct perf_evlist *evlist;
84 struct machine *host;
85 struct thread *current;
86 u64 base_time;
87 FILE *output;
88 unsigned long nr_events;
89 struct strlist *ev_qualifier;
90 struct {
91 size_t nr;
92 int *entries;
93 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030094 struct {
95 size_t nr;
96 pid_t *entries;
97 } filter_pids;
98 double duration_filter;
99 double runtime_ms;
100 struct {
101 u64 vfs_getname,
102 proc_getname;
103 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300104 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300105 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106 bool not_ev_qualifier;
107 bool live;
108 bool full_time;
109 bool sched;
110 bool multiple_threads;
111 bool summary;
112 bool summary_only;
113 bool show_comm;
114 bool show_tool_stats;
115 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300116 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117 bool force;
118 bool vfs_getname;
119 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300120 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300122
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300123struct tp_field {
124 int offset;
125 union {
126 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
127 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
128 };
129};
130
131#define TP_UINT_FIELD(bits) \
132static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
133{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500134 u##bits value; \
135 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
136 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300137}
138
139TP_UINT_FIELD(8);
140TP_UINT_FIELD(16);
141TP_UINT_FIELD(32);
142TP_UINT_FIELD(64);
143
144#define TP_UINT_FIELD__SWAPPED(bits) \
145static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
146{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500147 u##bits value; \
148 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300149 return bswap_##bits(value);\
150}
151
152TP_UINT_FIELD__SWAPPED(16);
153TP_UINT_FIELD__SWAPPED(32);
154TP_UINT_FIELD__SWAPPED(64);
155
156static int tp_field__init_uint(struct tp_field *field,
157 struct format_field *format_field,
158 bool needs_swap)
159{
160 field->offset = format_field->offset;
161
162 switch (format_field->size) {
163 case 1:
164 field->integer = tp_field__u8;
165 break;
166 case 2:
167 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
168 break;
169 case 4:
170 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
171 break;
172 case 8:
173 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
174 break;
175 default:
176 return -1;
177 }
178
179 return 0;
180}
181
182static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
183{
184 return sample->raw_data + field->offset;
185}
186
187static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
188{
189 field->offset = format_field->offset;
190 field->pointer = tp_field__ptr;
191 return 0;
192}
193
194struct syscall_tp {
195 struct tp_field id;
196 union {
197 struct tp_field args, ret;
198 };
199};
200
201static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
202 struct tp_field *field,
203 const char *name)
204{
205 struct format_field *format_field = perf_evsel__field(evsel, name);
206
207 if (format_field == NULL)
208 return -1;
209
210 return tp_field__init_uint(field, format_field, evsel->needs_swap);
211}
212
213#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
214 ({ struct syscall_tp *sc = evsel->priv;\
215 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
216
217static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
218 struct tp_field *field,
219 const char *name)
220{
221 struct format_field *format_field = perf_evsel__field(evsel, name);
222
223 if (format_field == NULL)
224 return -1;
225
226 return tp_field__init_ptr(field, format_field);
227}
228
229#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
230 ({ struct syscall_tp *sc = evsel->priv;\
231 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
232
233static void perf_evsel__delete_priv(struct perf_evsel *evsel)
234{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300235 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300236 perf_evsel__delete(evsel);
237}
238
Namhyung Kim96695d42013-11-12 08:51:45 -0300239static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
240{
241 evsel->priv = malloc(sizeof(struct syscall_tp));
242 if (evsel->priv != NULL) {
243 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
244 goto out_delete;
245
246 evsel->handler = handler;
247 return 0;
248 }
249
250 return -ENOMEM;
251
252out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300253 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300254 return -ENOENT;
255}
256
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300257static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300258{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300259 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300260
David Ahern9aca7f12013-12-04 19:41:39 -0700261 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200262 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700263 evsel = perf_evsel__newtp("syscalls", direction);
264
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200265 if (IS_ERR(evsel))
266 return NULL;
267
268 if (perf_evsel__init_syscall_tp(evsel, handler))
269 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300270
271 return evsel;
272
273out_delete:
274 perf_evsel__delete_priv(evsel);
275 return NULL;
276}
277
278#define perf_evsel__sc_tp_uint(evsel, name, sample) \
279 ({ struct syscall_tp *fields = evsel->priv; \
280 fields->name.integer(&fields->name, sample); })
281
282#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
283 ({ struct syscall_tp *fields = evsel->priv; \
284 fields->name.pointer(&fields->name, sample); })
285
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300286size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
287{
288 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300289
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300290 if (idx < 0 || idx >= sa->nr_entries)
291 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300292
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300293 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300300 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301}
302
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
307}
308
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309#define SCA_STRARRAY syscall_arg__scnprintf_strarray
310
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300311struct strarrays {
312 int nr_entries;
313 struct strarray **entries;
314};
315
316#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
317 .nr_entries = ARRAY_SIZE(array), \
318 .entries = array, \
319}
320
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300321size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
322 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300323{
324 struct strarrays *sas = arg->parm;
325 int i;
326
327 for (i = 0; i < sas->nr_entries; ++i) {
328 struct strarray *sa = sas->entries[i];
329 int idx = arg->val - sa->offset;
330
331 if (idx >= 0 && idx < sa->nr_entries) {
332 if (sa->entries[idx] == NULL)
333 break;
334 return scnprintf(bf, size, "%s", sa->entries[idx]);
335 }
336 }
337
338 return scnprintf(bf, size, "%d", arg->val);
339}
340
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300341#if defined(__i386__) || defined(__x86_64__)
342/*
343 * FIXME: Make this available to all arches as soon as the ioctl beautifier
344 * gets rewritten to support all arches.
345 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300346static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
347 struct syscall_arg *arg)
348{
349 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
350}
351
352#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300353#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300354
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300355#ifndef AT_FDCWD
356#define AT_FDCWD -100
357#endif
358
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300359static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
360 struct syscall_arg *arg)
361{
362 int fd = arg->val;
363
364 if (fd == AT_FDCWD)
365 return scnprintf(bf, size, "CWD");
366
367 return syscall_arg__scnprintf_fd(bf, size, arg);
368}
369
370#define SCA_FDAT syscall_arg__scnprintf_fd_at
371
372static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
373 struct syscall_arg *arg);
374
375#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
376
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300377size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300378{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300379 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300380}
381
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300382size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300383{
384 return scnprintf(bf, size, "%d", arg->val);
385}
386
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300387size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
388{
389 return scnprintf(bf, size, "%ld", arg->val);
390}
391
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300392static const char *bpf_cmd[] = {
393 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
394 "MAP_GET_NEXT_KEY", "PROG_LOAD",
395};
396static DEFINE_STRARRAY(bpf_cmd);
397
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300398static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
399static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300400
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300401static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
402static DEFINE_STRARRAY(itimers);
403
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300404static const char *keyctl_options[] = {
405 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
406 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
407 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
408 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
409 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
410};
411static DEFINE_STRARRAY(keyctl_options);
412
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300413static const char *whences[] = { "SET", "CUR", "END",
414#ifdef SEEK_DATA
415"DATA",
416#endif
417#ifdef SEEK_HOLE
418"HOLE",
419#endif
420};
421static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300422
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300423static const char *fcntl_cmds[] = {
424 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300425 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
426 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
427 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300428};
429static DEFINE_STRARRAY(fcntl_cmds);
430
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300431static const char *fcntl_linux_specific_cmds[] = {
432 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
433 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300434 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300435};
436
437static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
438
439static struct strarray *fcntl_cmds_arrays[] = {
440 &strarray__fcntl_cmds,
441 &strarray__fcntl_linux_specific_cmds,
442};
443
444static DEFINE_STRARRAYS(fcntl_cmds_arrays);
445
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300446static const char *rlimit_resources[] = {
447 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
448 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
449 "RTTIME",
450};
451static DEFINE_STRARRAY(rlimit_resources);
452
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300453static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
454static DEFINE_STRARRAY(sighow);
455
David Ahern4f8c1b72013-09-22 19:45:00 -0600456static const char *clockid[] = {
457 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300458 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
459 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600460};
461static DEFINE_STRARRAY(clockid);
462
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300463static const char *socket_families[] = {
464 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
465 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
466 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
467 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
468 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
469 "ALG", "NFC", "VSOCK",
470};
471static DEFINE_STRARRAY(socket_families);
472
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300473static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
474 struct syscall_arg *arg)
475{
476 size_t printed = 0;
477 int mode = arg->val;
478
479 if (mode == F_OK) /* 0 */
480 return scnprintf(bf, size, "F");
481#define P_MODE(n) \
482 if (mode & n##_OK) { \
483 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
484 mode &= ~n##_OK; \
485 }
486
487 P_MODE(R);
488 P_MODE(W);
489 P_MODE(X);
490#undef P_MODE
491
492 if (mode)
493 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
494
495 return printed;
496}
497
498#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
499
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300500static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
501 struct syscall_arg *arg);
502
503#define SCA_FILENAME syscall_arg__scnprintf_filename
504
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300505static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
506 struct syscall_arg *arg)
507{
508 int printed = 0, flags = arg->val;
509
510#define P_FLAG(n) \
511 if (flags & O_##n) { \
512 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
513 flags &= ~O_##n; \
514 }
515
516 P_FLAG(CLOEXEC);
517 P_FLAG(NONBLOCK);
518#undef P_FLAG
519
520 if (flags)
521 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
522
523 return printed;
524}
525
526#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
527
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300528#if defined(__i386__) || defined(__x86_64__)
529/*
530 * FIXME: Make this available to all arches.
531 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300532#define TCGETS 0x5401
533
534static const char *tioctls[] = {
535 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
536 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
537 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
538 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
539 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
540 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
541 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
542 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
543 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
544 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
545 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
546 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
547 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
548 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
549 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
550};
551
552static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300553#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300554
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300555#ifndef GRND_NONBLOCK
556#define GRND_NONBLOCK 0x0001
557#endif
558#ifndef GRND_RANDOM
559#define GRND_RANDOM 0x0002
560#endif
561
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300562static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
563 struct syscall_arg *arg)
564{
565 int printed = 0, flags = arg->val;
566
567#define P_FLAG(n) \
568 if (flags & GRND_##n) { \
569 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
570 flags &= ~GRND_##n; \
571 }
572
573 P_FLAG(RANDOM);
574 P_FLAG(NONBLOCK);
575#undef P_FLAG
576
577 if (flags)
578 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
579
580 return printed;
581}
582
583#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
584
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300585#define STRARRAY(name, array) \
586 { .scnprintf = SCA_STRARRAY, \
587 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300588
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300589#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300590#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300591#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300592#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300593#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300594#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300595#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300596#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300597#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300598#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300599#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300600#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300601#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300602#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300603
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300604struct syscall_arg_fmt {
605 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
606 void *parm;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300607 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300608};
609
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300610static struct syscall_fmt {
611 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300612 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300613 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300614 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300615 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300616 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300617} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300618 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300619 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300620 { .name = "arch_prctl", .alias = "prctl", },
621 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300623 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300624 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300625 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300626 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300627 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300628 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300629 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300630 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300631 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300632 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300633 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300634 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300635 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300636 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300638 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300639 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300640 .parm = &strarrays__fcntl_cmds_arrays,
641 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300642 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300643 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300644 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300645 { .name = "fstat", .alias = "newfstat", },
646 { .name = "fstatat", .alias = "newfstatat", },
647 { .name = "futex",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300648 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300649 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300650 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300651 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300652 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300653 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300654 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300655 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300656 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300657 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300658 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300659 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300660 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300661 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300662#if defined(__i386__) || defined(__x86_64__)
663/*
664 * FIXME: Make this available to all arches.
665 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300666 [1] = { .scnprintf = SCA_STRHEXARRAY, /* cmd */
667 .parm = &strarray__tioctls, },
668 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300669#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300670 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300671#endif
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300672 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300673 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300676 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300677 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300678 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300679 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300680 { .name = "lstat", .alias = "newlstat", },
681 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
683 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300684 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300685 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300686 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300688 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300689 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300690 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300691 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300692 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200693/* The standard mmap maps to old_mmap on s390x */
694#if defined(__s390x__)
695 .alias = "old_mmap",
696#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300697 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
698 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
699 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300700 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300701 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
702 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300705 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300706 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
707 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
708 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300710 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300711 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300717 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300718 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300719 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300720 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
721 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300722 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300723 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
724 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300726 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
727 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
728 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300730 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300731 { .name = "poll", .timeout = true, },
732 { .name = "ppoll", .timeout = true, },
733 { .name = "pread", .alias = "pread64", },
734 { .name = "preadv", .alias = "pread", },
735 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300736 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300737 { .name = "pwrite", .alias = "pwrite64", },
738 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300745 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300746 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300747 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300748 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300749 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300750 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300756 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300757 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300758 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300759 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
760 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300761 { .name = "select", .timeout = true, },
762 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300764 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300765 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300766 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300768 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300769 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300770 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300771 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300772 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300773 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300774 .arg = { [0] = STRARRAY(family, socket_families),
775 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300776 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300777 .arg = { [0] = STRARRAY(family, socket_families),
778 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300779 { .name = "stat", .alias = "newstat", },
780 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300781 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
782 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
783 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300784 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300785 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300786 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300787 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300788 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300789 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300790 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300791 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300792 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300793 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300794 { .name = "uname", .alias = "newuname", },
795 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300796 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300797 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300798 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300799 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300800 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300801 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300802 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300803};
804
805static int syscall_fmt__cmp(const void *name, const void *fmtp)
806{
807 const struct syscall_fmt *fmt = fmtp;
808 return strcmp(name, fmt->name);
809}
810
811static struct syscall_fmt *syscall_fmt__find(const char *name)
812{
813 const int nmemb = ARRAY_SIZE(syscall_fmts);
814 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
815}
816
817struct syscall {
818 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300819 int nr_args;
820 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300821 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300822 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300823 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300824 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300825};
826
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300827/*
828 * We need to have this 'calculated' boolean because in some cases we really
829 * don't know what is the duration of a syscall, for instance, when we start
830 * a session and some threads are waiting for a syscall to finish, say 'poll',
831 * in which case all we can do is to print "( ? ) for duration and for the
832 * start timestamp.
833 */
834static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200835{
836 double duration = (double)t / NSEC_PER_MSEC;
837 size_t printed = fprintf(fp, "(");
838
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300839 if (!calculated)
840 printed += fprintf(fp, " ? ");
841 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200842 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
843 else if (duration >= 0.01)
844 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
845 else
846 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300847 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200848}
849
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300850/**
851 * filename.ptr: The filename char pointer that will be vfs_getname'd
852 * filename.entry_str_pos: Where to insert the string translated from
853 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300854 * ret_scnprintf: syscall args may set this to a different syscall return
855 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300856 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300857struct thread_trace {
858 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300859 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300860 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400861 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300862 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300863 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300864 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300865 struct {
866 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300867 short int entry_str_pos;
868 bool pending_open;
869 unsigned int namelen;
870 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300871 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300872 struct {
873 int max;
874 char **table;
875 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600876
877 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300878};
879
880static struct thread_trace *thread_trace__new(void)
881{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300882 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
883
884 if (ttrace)
885 ttrace->paths.max = -1;
886
David Ahernbf2575c2013-10-08 21:26:53 -0600887 ttrace->syscall_stats = intlist__new(NULL);
888
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300889 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890}
891
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300892static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300893{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300894 struct thread_trace *ttrace;
895
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300896 if (thread == NULL)
897 goto fail;
898
Namhyung Kim89dceb22014-10-06 09:46:03 +0900899 if (thread__priv(thread) == NULL)
900 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300901
Namhyung Kim89dceb22014-10-06 09:46:03 +0900902 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300903 goto fail;
904
Namhyung Kim89dceb22014-10-06 09:46:03 +0900905 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300906 ++ttrace->nr_events;
907
908 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300910 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300911 "WARNING: not enough memory, dropping samples!\n");
912 return NULL;
913}
914
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300915
916void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300917 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300918{
919 struct thread_trace *ttrace = thread__priv(arg->thread);
920
921 ttrace->ret_scnprintf = ret_scnprintf;
922}
923
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400924#define TRACE_PFMAJ (1 << 0)
925#define TRACE_PFMIN (1 << 1)
926
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300927static const size_t trace__entry_str_size = 2048;
928
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300929static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300930{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900931 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300932
933 if (fd > ttrace->paths.max) {
934 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
935
936 if (npath == NULL)
937 return -1;
938
939 if (ttrace->paths.max != -1) {
940 memset(npath + ttrace->paths.max + 1, 0,
941 (fd - ttrace->paths.max) * sizeof(char *));
942 } else {
943 memset(npath, 0, (fd + 1) * sizeof(char *));
944 }
945
946 ttrace->paths.table = npath;
947 ttrace->paths.max = fd;
948 }
949
950 ttrace->paths.table[fd] = strdup(pathname);
951
952 return ttrace->paths.table[fd] != NULL ? 0 : -1;
953}
954
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300955static int thread__read_fd_path(struct thread *thread, int fd)
956{
957 char linkname[PATH_MAX], pathname[PATH_MAX];
958 struct stat st;
959 int ret;
960
961 if (thread->pid_ == thread->tid) {
962 scnprintf(linkname, sizeof(linkname),
963 "/proc/%d/fd/%d", thread->pid_, fd);
964 } else {
965 scnprintf(linkname, sizeof(linkname),
966 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
967 }
968
969 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
970 return -1;
971
972 ret = readlink(linkname, pathname, sizeof(pathname));
973
974 if (ret < 0 || ret > st.st_size)
975 return -1;
976
977 pathname[ret] = '\0';
978 return trace__set_fd_pathname(thread, fd, pathname);
979}
980
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300981static const char *thread__fd_path(struct thread *thread, int fd,
982 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300983{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900984 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985
986 if (ttrace == NULL)
987 return NULL;
988
989 if (fd < 0)
990 return NULL;
991
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300992 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300993 if (!trace->live)
994 return NULL;
995 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300996 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300997 return NULL;
998 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300999
1000 return ttrace->paths.table[fd];
1001}
1002
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001003size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004{
1005 int fd = arg->val;
1006 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001007 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001008
1009 if (path)
1010 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1011
1012 return printed;
1013}
1014
1015static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1016 struct syscall_arg *arg)
1017{
1018 int fd = arg->val;
1019 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001020 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001022 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1023 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001024
1025 return printed;
1026}
1027
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001028static void thread__set_filename_pos(struct thread *thread, const char *bf,
1029 unsigned long ptr)
1030{
1031 struct thread_trace *ttrace = thread__priv(thread);
1032
1033 ttrace->filename.ptr = ptr;
1034 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1035}
1036
1037static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1038 struct syscall_arg *arg)
1039{
1040 unsigned long ptr = arg->val;
1041
1042 if (!arg->trace->vfs_getname)
1043 return scnprintf(bf, size, "%#x", ptr);
1044
1045 thread__set_filename_pos(arg->thread, bf, ptr);
1046 return 0;
1047}
1048
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001049static bool trace__filter_duration(struct trace *trace, double t)
1050{
1051 return t < (trace->duration_filter * NSEC_PER_MSEC);
1052}
1053
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001054static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001055{
1056 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1057
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001058 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001059}
1060
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001061/*
1062 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1063 * using ttrace->entry_time for a thread that receives a sys_exit without
1064 * first having received a sys_enter ("poll" issued before tracing session
1065 * starts, lost sys_enter exit due to ring buffer overflow).
1066 */
1067static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1068{
1069 if (tstamp > 0)
1070 return __trace__fprintf_tstamp(trace, tstamp, fp);
1071
1072 return fprintf(fp, " ? ");
1073}
1074
Namhyung Kimf15eb532012-10-05 14:02:16 +09001075static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001076static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001077
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001078static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001079{
1080 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001081 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001082}
1083
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001084static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001085 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086{
1087 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001088 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001089
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001090 if (trace->multiple_threads) {
1091 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001092 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001093 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001094 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001095
1096 return printed;
1097}
1098
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001099static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001100 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101{
1102 int ret = 0;
1103
1104 switch (event->header.type) {
1105 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001106 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001108 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001109 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001111 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001112 break;
1113 }
1114
1115 return ret;
1116}
1117
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001118static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001119 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001120 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121 struct machine *machine)
1122{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001123 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001124 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125}
1126
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001127static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1128{
1129 struct machine *machine = vmachine;
1130
1131 if (machine->kptr_restrict_warned)
1132 return NULL;
1133
1134 if (symbol_conf.kptr_restrict) {
1135 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1136 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1137 "Kernel samples will not be resolved.\n");
1138 machine->kptr_restrict_warned = true;
1139 return NULL;
1140 }
1141
1142 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1143}
1144
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1146{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001147 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148
1149 if (err)
1150 return err;
1151
David Ahern8fb598e2013-09-28 13:13:00 -06001152 trace->host = machine__new_host();
1153 if (trace->host == NULL)
1154 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001156 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001157 return -errno;
1158
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001159 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001160 evlist->threads, trace__tool_process, false,
1161 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001162 if (err)
1163 symbol__exit();
1164
1165 return err;
1166}
1167
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001168static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1169{
1170 int idx;
1171
1172 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1173 if (sc->arg_fmt == NULL)
1174 return -1;
1175
1176 for (idx = 0; idx < nr_args; ++idx) {
1177 if (sc->fmt)
1178 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1179 }
1180
1181 sc->nr_args = nr_args;
1182 return 0;
1183}
1184
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001185static int syscall__set_arg_fmts(struct syscall *sc)
1186{
1187 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001188 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001189
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001190 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001191 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1192 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001193
1194 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001195 (strcmp(field->name, "filename") == 0 ||
1196 strcmp(field->name, "path") == 0 ||
1197 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001198 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001199 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001200 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001201 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001202 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001203 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001204 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001205 else if ((strcmp(field->type, "int") == 0 ||
1206 strcmp(field->type, "unsigned int") == 0 ||
1207 strcmp(field->type, "long") == 0) &&
1208 (len = strlen(field->name)) >= 2 &&
1209 strcmp(field->name + len - 2, "fd") == 0) {
1210 /*
1211 * /sys/kernel/tracing/events/syscalls/sys_enter*
1212 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1213 * 65 int
1214 * 23 unsigned int
1215 * 7 unsigned long
1216 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001217 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001218 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001219 }
1220
1221 return 0;
1222}
1223
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001224static int trace__read_syscall_info(struct trace *trace, int id)
1225{
1226 char tp_name[128];
1227 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001228 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001229
1230 if (name == NULL)
1231 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001232
1233 if (id > trace->syscalls.max) {
1234 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1235
1236 if (nsyscalls == NULL)
1237 return -1;
1238
1239 if (trace->syscalls.max != -1) {
1240 memset(nsyscalls + trace->syscalls.max + 1, 0,
1241 (id - trace->syscalls.max) * sizeof(*sc));
1242 } else {
1243 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1244 }
1245
1246 trace->syscalls.table = nsyscalls;
1247 trace->syscalls.max = id;
1248 }
1249
1250 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001251 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001252
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001253 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001254
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001255 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001256 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001257
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001258 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001259 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001260 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001261 }
1262
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001263 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1264 return -1;
1265
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001266 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001267 return -1;
1268
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001269 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001270 /*
1271 * We need to check and discard the first variable '__syscall_nr'
1272 * or 'nr' that mean the syscall number. It is needless here.
1273 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1274 */
1275 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001276 sc->args = sc->args->next;
1277 --sc->nr_args;
1278 }
1279
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001280 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1281
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001282 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001283}
1284
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001285static int trace__validate_ev_qualifier(struct trace *trace)
1286{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001287 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001288 struct str_node *pos;
1289
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001290 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1291 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1292 sizeof(trace->ev_qualifier_ids.entries[0]));
1293
1294 if (trace->ev_qualifier_ids.entries == NULL) {
1295 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1296 trace->output);
1297 err = -EINVAL;
1298 goto out;
1299 }
1300
1301 i = 0;
1302
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001303 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001304 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001305 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001306
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001307 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001308 if (err == 0) {
1309 fputs("Error:\tInvalid syscall ", trace->output);
1310 err = -EINVAL;
1311 } else {
1312 fputs(", ", trace->output);
1313 }
1314
1315 fputs(sc, trace->output);
1316 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001317
1318 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001319 }
1320
1321 if (err < 0) {
1322 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1323 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001324 zfree(&trace->ev_qualifier_ids.entries);
1325 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001326 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001327out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001328 return err;
1329}
1330
David Ahern55d43bca2015-02-19 15:00:22 -05001331/*
1332 * args is to be interpreted as a series of longs but we need to handle
1333 * 8-byte unaligned accesses. args points to raw_data within the event
1334 * and raw_data is guaranteed to be 8-byte unaligned because it is
1335 * preceded by raw_size which is a u32. So we need to copy args to a temp
1336 * variable to read it. Most notably this avoids extended load instructions
1337 * on unaligned addresses
1338 */
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001339static unsigned long __syscall_arg__val(unsigned char *args, u8 idx)
1340{
1341 unsigned long val;
1342 unsigned char *p = args + sizeof(unsigned long) * idx;
1343
1344 memcpy(&val, p, sizeof(val));
1345 return val;
1346}
1347
1348unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
1349{
1350 return __syscall_arg__val(arg->args, idx);
1351}
David Ahern55d43bca2015-02-19 15:00:22 -05001352
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001353static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1354 struct syscall_arg *arg, unsigned long val)
1355{
1356 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1357 arg->val = val;
1358 if (sc->arg_fmt[arg->idx].parm)
1359 arg->parm = sc->arg_fmt[arg->idx].parm;
1360 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1361 }
1362 return scnprintf(bf, size, "%ld", val);
1363}
1364
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001365static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001366 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001367 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001368{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001369 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001370 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001371 u8 bit = 1;
1372 struct syscall_arg arg = {
1373 .args = args,
1374 .idx = 0,
1375 .mask = 0,
1376 .trace = trace,
1377 .thread = thread,
1378 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001379 struct thread_trace *ttrace = thread__priv(thread);
1380
1381 /*
1382 * Things like fcntl will set this in its 'cmd' formatter to pick the
1383 * right formatter for the return value (an fd? file flags?), which is
1384 * not needed for syscalls that always return a given type, say an fd.
1385 */
1386 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001387
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001388 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001389 struct format_field *field;
1390
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001391 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001392 field = field->next, ++arg.idx, bit <<= 1) {
1393 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001394 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001395
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001396 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001397
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001398 /*
1399 * Suppress this argument if its value is zero and
1400 * and we don't have a string associated in an
1401 * strarray for it.
1402 */
David Ahern55d43bca2015-02-19 15:00:22 -05001403 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001404 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001405 (sc->arg_fmt[arg.idx].show_zero ||
1406 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001407 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1408 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001409 continue;
1410
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001411 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001412 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001413 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001414 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001415 } else if (IS_ERR(sc->tp_format)) {
1416 /*
1417 * If we managed to read the tracepoint /format file, then we
1418 * may end up not having any args, like with gettid(), so only
1419 * print the raw args when we didn't manage to read it.
1420 */
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001421 while (arg.idx < 6) {
1422 if (arg.mask & bit)
1423 goto next_arg;
1424 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001425 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001426 "%sarg%d: ", printed ? ", " : "", arg.idx);
1427 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1428next_arg:
1429 ++arg.idx;
1430 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001431 }
1432 }
1433
1434 return printed;
1435}
1436
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001437typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001438 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001439 struct perf_sample *sample);
1440
1441static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001442 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001443{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001444
1445 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001446
1447 /*
1448 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1449 * before that, leaving at a higher verbosity level till that is
1450 * explained. Reproduced with plain ftrace with:
1451 *
1452 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1453 * grep "NR -1 " /t/trace_pipe
1454 *
1455 * After generating some load on the machine.
1456 */
1457 if (verbose > 1) {
1458 static u64 n;
1459 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1460 id, perf_evsel__name(evsel), ++n);
1461 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001462 return NULL;
1463 }
1464
1465 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1466 trace__read_syscall_info(trace, id))
1467 goto out_cant_read;
1468
1469 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1470 goto out_cant_read;
1471
1472 return &trace->syscalls.table[id];
1473
1474out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001475 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001476 fprintf(trace->output, "Problems reading syscall %d", id);
1477 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1478 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1479 fputs(" information\n", trace->output);
1480 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001481 return NULL;
1482}
1483
David Ahernbf2575c2013-10-08 21:26:53 -06001484static void thread__update_stats(struct thread_trace *ttrace,
1485 int id, struct perf_sample *sample)
1486{
1487 struct int_node *inode;
1488 struct stats *stats;
1489 u64 duration = 0;
1490
1491 inode = intlist__findnew(ttrace->syscall_stats, id);
1492 if (inode == NULL)
1493 return;
1494
1495 stats = inode->priv;
1496 if (stats == NULL) {
1497 stats = malloc(sizeof(struct stats));
1498 if (stats == NULL)
1499 return;
1500 init_stats(stats);
1501 inode->priv = stats;
1502 }
1503
1504 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1505 duration = sample->time - ttrace->entry_time;
1506
1507 update_stats(stats, duration);
1508}
1509
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001510static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1511{
1512 struct thread_trace *ttrace;
1513 u64 duration;
1514 size_t printed;
1515
1516 if (trace->current == NULL)
1517 return 0;
1518
1519 ttrace = thread__priv(trace->current);
1520
1521 if (!ttrace->entry_pending)
1522 return 0;
1523
1524 duration = sample->time - ttrace->entry_time;
1525
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001526 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001527 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1528 ttrace->entry_pending = false;
1529
1530 return printed;
1531}
1532
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001533static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001534 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001535 struct perf_sample *sample)
1536{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001537 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001538 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001539 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001540 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001541 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001542 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001543 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001544
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001545 if (sc == NULL)
1546 return -1;
1547
David Ahern8fb598e2013-09-28 13:13:00 -06001548 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001549 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001550 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001551 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001552
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001553 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001554
1555 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001556 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001557 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001558 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001559 }
1560
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001561 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001562 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001563
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001564 ttrace->entry_time = sample->time;
1565 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001566 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001567
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001568 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001569 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001570
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001571 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001572 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001573 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001574 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001575 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001576 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001577 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001578 /* See trace__vfs_getname & trace__sys_exit */
1579 ttrace->filename.pending_open = false;
1580 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001581
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001582 if (trace->current != thread) {
1583 thread__put(trace->current);
1584 trace->current = thread__get(thread);
1585 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001586 err = 0;
1587out_put:
1588 thread__put(thread);
1589 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001590}
1591
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001592static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1593 struct perf_sample *sample,
1594 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001595{
1596 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001597
1598 if (machine__resolve(trace->host, &al, sample) < 0 ||
1599 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1600 return -1;
1601
1602 return 0;
1603}
1604
1605static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1606{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001607 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001608 const unsigned int print_opts = EVSEL__PRINT_SYM |
1609 EVSEL__PRINT_DSO |
1610 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001611
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001612 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001613}
1614
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001615static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001616 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001617 struct perf_sample *sample)
1618{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001619 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001620 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001621 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001622 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001623 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001624 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001625 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001626
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001627 if (sc == NULL)
1628 return -1;
1629
David Ahern8fb598e2013-09-28 13:13:00 -06001630 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001631 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001632 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001633 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001634
David Ahernbf2575c2013-10-08 21:26:53 -06001635 if (trace->summary)
1636 thread__update_stats(ttrace, id, sample);
1637
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001638 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001639
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001640 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001641 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1642 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001643 ++trace->stats.vfs_getname;
1644 }
1645
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001646 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001647 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001648 if (trace__filter_duration(trace, duration))
1649 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001650 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001651 } else if (trace->duration_filter)
1652 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001653
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001654 if (sample->callchain) {
1655 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1656 if (callchain_ret == 0) {
1657 if (callchain_cursor.nr < trace->min_stack)
1658 goto out;
1659 callchain_ret = 1;
1660 }
1661 }
1662
David Ahernfd2eaba2013-11-12 09:31:15 -07001663 if (trace->summary_only)
1664 goto out;
1665
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001666 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001667
1668 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001669 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001670 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001671 fprintf(trace->output, " ... [");
1672 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1673 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001674 }
1675
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001676 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001677 if (ret < 0)
1678 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001679signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001680 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001681 } else if (ret < 0) {
1682errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001683 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001684 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001685 *e = audit_errno_to_name(-ret);
1686
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001687 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001688 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001689 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001690 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001691 else if (ttrace->ret_scnprintf) {
1692 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001693 struct syscall_arg arg = {
1694 .val = ret,
1695 .thread = thread,
1696 .trace = trace,
1697 };
1698 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001699 ttrace->ret_scnprintf = NULL;
1700 fprintf(trace->output, ") = %s", bf);
1701 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001702 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001703 else if (sc->fmt->errpid) {
1704 struct thread *child = machine__find_thread(trace->host, ret, ret);
1705
1706 if (child != NULL) {
1707 fprintf(trace->output, ") = %ld", ret);
1708 if (child->comm_set)
1709 fprintf(trace->output, " (%s)", thread__comm_str(child));
1710 thread__put(child);
1711 }
1712 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001713 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001714
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001715 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001716
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001717 if (callchain_ret > 0)
1718 trace__fprintf_callchain(trace, sample);
1719 else if (callchain_ret < 0)
1720 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001721out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001722 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001723 err = 0;
1724out_put:
1725 thread__put(thread);
1726 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001727}
1728
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001729static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001730 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001731 struct perf_sample *sample)
1732{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001733 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1734 struct thread_trace *ttrace;
1735 size_t filename_len, entry_str_len, to_move;
1736 ssize_t remaining_space;
1737 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001738 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001739
1740 if (!thread)
1741 goto out;
1742
1743 ttrace = thread__priv(thread);
1744 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001745 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001746
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001747 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001748 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001749 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001750
1751 if (ttrace->filename.namelen < filename_len) {
1752 char *f = realloc(ttrace->filename.name, filename_len + 1);
1753
1754 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001755 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001756
1757 ttrace->filename.namelen = filename_len;
1758 ttrace->filename.name = f;
1759 }
1760
1761 strcpy(ttrace->filename.name, filename);
1762 ttrace->filename.pending_open = true;
1763
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001764 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001765 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001766
1767 entry_str_len = strlen(ttrace->entry_str);
1768 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1769 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001770 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001771
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001772 if (filename_len > (size_t)remaining_space) {
1773 filename += filename_len - remaining_space;
1774 filename_len = remaining_space;
1775 }
1776
1777 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1778 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1779 memmove(pos + filename_len, pos, to_move);
1780 memcpy(pos, filename, filename_len);
1781
1782 ttrace->filename.ptr = 0;
1783 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001784out_put:
1785 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001786out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001787 return 0;
1788}
1789
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001790static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001791 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001792 struct perf_sample *sample)
1793{
1794 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1795 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001796 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001797 sample->pid,
1798 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001799 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001800
1801 if (ttrace == NULL)
1802 goto out_dump;
1803
1804 ttrace->runtime_ms += runtime_ms;
1805 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001806out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001807 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001808 return 0;
1809
1810out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001811 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001812 evsel->name,
1813 perf_evsel__strval(evsel, sample, "comm"),
1814 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1815 runtime,
1816 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001817 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001818}
1819
Wang Nan1d6c9402016-02-26 09:31:55 +00001820static void bpf_output__printer(enum binary_printer_ops op,
1821 unsigned int val, void *extra)
1822{
1823 FILE *output = extra;
1824 unsigned char ch = (unsigned char)val;
1825
1826 switch (op) {
1827 case BINARY_PRINT_CHAR_DATA:
1828 fprintf(output, "%c", isprint(ch) ? ch : '.');
1829 break;
1830 case BINARY_PRINT_DATA_BEGIN:
1831 case BINARY_PRINT_LINE_BEGIN:
1832 case BINARY_PRINT_ADDR:
1833 case BINARY_PRINT_NUM_DATA:
1834 case BINARY_PRINT_NUM_PAD:
1835 case BINARY_PRINT_SEP:
1836 case BINARY_PRINT_CHAR_PAD:
1837 case BINARY_PRINT_LINE_END:
1838 case BINARY_PRINT_DATA_END:
1839 default:
1840 break;
1841 }
1842}
1843
1844static void bpf_output__fprintf(struct trace *trace,
1845 struct perf_sample *sample)
1846{
1847 print_binary(sample->raw_data, sample->raw_size, 8,
1848 bpf_output__printer, trace->output);
1849}
1850
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001851static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1852 union perf_event *event __maybe_unused,
1853 struct perf_sample *sample)
1854{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001855 int callchain_ret = 0;
1856
1857 if (sample->callchain) {
1858 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1859 if (callchain_ret == 0) {
1860 if (callchain_cursor.nr < trace->min_stack)
1861 goto out;
1862 callchain_ret = 1;
1863 }
1864 }
1865
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001866 trace__printf_interrupted_entry(trace, sample);
1867 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001868
1869 if (trace->trace_syscalls)
1870 fprintf(trace->output, "( ): ");
1871
1872 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001873
Wang Nan1d6c9402016-02-26 09:31:55 +00001874 if (perf_evsel__is_bpf_output(evsel)) {
1875 bpf_output__fprintf(trace, sample);
1876 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001877 event_format__fprintf(evsel->tp_format, sample->cpu,
1878 sample->raw_data, sample->raw_size,
1879 trace->output);
1880 }
1881
1882 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001883
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001884 if (callchain_ret > 0)
1885 trace__fprintf_callchain(trace, sample);
1886 else if (callchain_ret < 0)
1887 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1888out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001889 return 0;
1890}
1891
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001892static void print_location(FILE *f, struct perf_sample *sample,
1893 struct addr_location *al,
1894 bool print_dso, bool print_sym)
1895{
1896
Namhyung Kimbb963e12017-02-17 17:17:38 +09001897 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001898 fprintf(f, "%s@", al->map->dso->long_name);
1899
Namhyung Kimbb963e12017-02-17 17:17:38 +09001900 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001901 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001902 al->addr - al->sym->start);
1903 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001904 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001905 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001906 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001907}
1908
1909static int trace__pgfault(struct trace *trace,
1910 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001911 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001912 struct perf_sample *sample)
1913{
1914 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001915 struct addr_location al;
1916 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001917 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001918 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001919 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001920
1921 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001922
1923 if (sample->callchain) {
1924 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1925 if (callchain_ret == 0) {
1926 if (callchain_cursor.nr < trace->min_stack)
1927 goto out_put;
1928 callchain_ret = 1;
1929 }
1930 }
1931
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001932 ttrace = thread__trace(thread, trace->output);
1933 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001934 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001935
1936 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1937 ttrace->pfmaj++;
1938 else
1939 ttrace->pfmin++;
1940
1941 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001942 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001943
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001944 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001945 sample->ip, &al);
1946
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001947 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001948
1949 fprintf(trace->output, "%sfault [",
1950 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1951 "maj" : "min");
1952
1953 print_location(trace->output, sample, &al, false, true);
1954
1955 fprintf(trace->output, "] => ");
1956
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001957 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001958 sample->addr, &al);
1959
1960 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001961 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001962 MAP__FUNCTION, sample->addr, &al);
1963
1964 if (al.map)
1965 map_type = 'x';
1966 else
1967 map_type = '?';
1968 }
1969
1970 print_location(trace->output, sample, &al, true, false);
1971
1972 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001973
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001974 if (callchain_ret > 0)
1975 trace__fprintf_callchain(trace, sample);
1976 else if (callchain_ret < 0)
1977 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001978out:
1979 err = 0;
1980out_put:
1981 thread__put(thread);
1982 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001983}
1984
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001985static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001986 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001987 struct perf_sample *sample)
1988{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001989 /*
1990 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1991 * and don't use sample->time unconditionally, we may end up having
1992 * some other event in the future without PERF_SAMPLE_TIME for good
1993 * reason, i.e. we may not be interested in its timestamps, just in
1994 * it taking place, picking some piece of information when it
1995 * appears in our event stream (vfs_getname comes to mind).
1996 */
1997 if (trace->base_time == 0 && !trace->full_time &&
1998 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001999 trace->base_time = sample->time;
2000}
2001
David Ahern6810fc92013-08-28 22:29:52 -06002002static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002003 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002004 struct perf_sample *sample,
2005 struct perf_evsel *evsel,
2006 struct machine *machine __maybe_unused)
2007{
2008 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002009 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002010 int err = 0;
2011
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002012 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002013
David Ahernaa07df62016-11-25 09:29:52 -07002014 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2015 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002016 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002017
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002018 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002019
David Ahern31605652013-12-04 19:41:41 -07002020 if (handler) {
2021 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002022 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002023 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002024out:
2025 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002026 return err;
2027}
2028
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002029static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002030{
2031 unsigned int rec_argc, i, j;
2032 const char **rec_argv;
2033 const char * const record_args[] = {
2034 "record",
2035 "-R",
2036 "-m", "1024",
2037 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002038 };
2039
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002040 const char * const sc_args[] = { "-e", };
2041 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2042 const char * const majpf_args[] = { "-e", "major-faults" };
2043 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2044 const char * const minpf_args[] = { "-e", "minor-faults" };
2045 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2046
David Ahern9aca7f12013-12-04 19:41:39 -07002047 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002048 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2049 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002050 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2051
2052 if (rec_argv == NULL)
2053 return -ENOMEM;
2054
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002055 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002056 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002057 rec_argv[j++] = record_args[i];
2058
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002059 if (trace->trace_syscalls) {
2060 for (i = 0; i < sc_args_nr; i++)
2061 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002062
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002063 /* event string may be different for older kernels - e.g., RHEL6 */
2064 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2065 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2066 else if (is_valid_tracepoint("syscalls:sys_enter"))
2067 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2068 else {
2069 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2070 return -1;
2071 }
David Ahern9aca7f12013-12-04 19:41:39 -07002072 }
David Ahern9aca7f12013-12-04 19:41:39 -07002073
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002074 if (trace->trace_pgfaults & TRACE_PFMAJ)
2075 for (i = 0; i < majpf_args_nr; i++)
2076 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002077
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002078 if (trace->trace_pgfaults & TRACE_PFMIN)
2079 for (i = 0; i < minpf_args_nr; i++)
2080 rec_argv[j++] = minpf_args[i];
2081
2082 for (i = 0; i < (unsigned int)argc; i++)
2083 rec_argv[j++] = argv[i];
2084
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002085 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002086}
2087
David Ahernbf2575c2013-10-08 21:26:53 -06002088static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2089
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002090static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002091{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002092 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002093
2094 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002095 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002096
2097 if (perf_evsel__field(evsel, "pathname") == NULL) {
2098 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002099 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002100 }
2101
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002102 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002103 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002104 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002105}
2106
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002107static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002108{
2109 struct perf_evsel *evsel;
2110 struct perf_event_attr attr = {
2111 .type = PERF_TYPE_SOFTWARE,
2112 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002113 };
2114
2115 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002116 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002117
2118 event_attr_init(&attr);
2119
2120 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002121 if (evsel)
2122 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002123
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002124 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002125}
2126
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002127static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2128{
2129 const u32 type = event->header.type;
2130 struct perf_evsel *evsel;
2131
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002132 if (type != PERF_RECORD_SAMPLE) {
2133 trace__process_event(trace, trace->host, event, sample);
2134 return;
2135 }
2136
2137 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2138 if (evsel == NULL) {
2139 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2140 return;
2141 }
2142
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002143 trace__set_base_time(trace, evsel, sample);
2144
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002145 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2146 sample->raw_data == NULL) {
2147 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2148 perf_evsel__name(evsel), sample->tid,
2149 sample->cpu, sample->raw_size);
2150 } else {
2151 tracepoint_handler handler = evsel->handler;
2152 handler(trace, evsel, event, sample);
2153 }
2154}
2155
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002156static int trace__add_syscall_newtp(struct trace *trace)
2157{
2158 int ret = -1;
2159 struct perf_evlist *evlist = trace->evlist;
2160 struct perf_evsel *sys_enter, *sys_exit;
2161
2162 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2163 if (sys_enter == NULL)
2164 goto out;
2165
2166 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2167 goto out_delete_sys_enter;
2168
2169 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2170 if (sys_exit == NULL)
2171 goto out_delete_sys_enter;
2172
2173 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2174 goto out_delete_sys_exit;
2175
2176 perf_evlist__add(evlist, sys_enter);
2177 perf_evlist__add(evlist, sys_exit);
2178
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002179 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002180 /*
2181 * We're interested only in the user space callchain
2182 * leading to the syscall, allow overriding that for
2183 * debugging reasons using --kernel_syscall_callchains
2184 */
2185 sys_exit->attr.exclude_callchain_kernel = 1;
2186 }
2187
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002188 trace->syscalls.events.sys_enter = sys_enter;
2189 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002190
2191 ret = 0;
2192out:
2193 return ret;
2194
2195out_delete_sys_exit:
2196 perf_evsel__delete_priv(sys_exit);
2197out_delete_sys_enter:
2198 perf_evsel__delete_priv(sys_enter);
2199 goto out;
2200}
2201
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002202static int trace__set_ev_qualifier_filter(struct trace *trace)
2203{
2204 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002205 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002206 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2207 trace->ev_qualifier_ids.nr,
2208 trace->ev_qualifier_ids.entries);
2209
2210 if (filter == NULL)
2211 goto out_enomem;
2212
Mathieu Poirier3541c032016-09-16 08:44:04 -06002213 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2214 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002215 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002216 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002217 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002218
2219 free(filter);
2220out:
2221 return err;
2222out_enomem:
2223 errno = ENOMEM;
2224 goto out;
2225}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002226
Namhyung Kimf15eb532012-10-05 14:02:16 +09002227static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002228{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002229 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002230 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002231 int err = -1, i;
2232 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002233 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002234 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002235
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002236 trace->live = true;
2237
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002238 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002239 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002240
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002241 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002242 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002243
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002244 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2245 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2246 if (pgfault_maj == NULL)
2247 goto out_error_mem;
2248 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002249 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002250
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002251 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2252 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2253 if (pgfault_min == NULL)
2254 goto out_error_mem;
2255 perf_evlist__add(evlist, pgfault_min);
2256 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002257
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002258 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002259 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2260 trace__sched_stat_runtime))
2261 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002262
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002263 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2264 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002265 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002266 goto out_delete_evlist;
2267 }
2268
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002269 err = trace__symbols_init(trace, evlist);
2270 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002271 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002272 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002273 }
2274
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002275 perf_evlist__config(evlist, &trace->opts, NULL);
2276
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002277 if (callchain_param.enabled) {
2278 bool use_identifier = false;
2279
2280 if (trace->syscalls.events.sys_exit) {
2281 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2282 &trace->opts, &callchain_param);
2283 use_identifier = true;
2284 }
2285
2286 if (pgfault_maj) {
2287 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2288 use_identifier = true;
2289 }
2290
2291 if (pgfault_min) {
2292 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2293 use_identifier = true;
2294 }
2295
2296 if (use_identifier) {
2297 /*
2298 * Now we have evsels with different sample_ids, use
2299 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2300 * from a fixed position in each ring buffer record.
2301 *
2302 * As of this the changeset introducing this comment, this
2303 * isn't strictly needed, as the fields that can come before
2304 * PERF_SAMPLE_ID are all used, but we'll probably disable
2305 * some of those for things like copying the payload of
2306 * pointer syscall arguments, and for vfs_getname we don't
2307 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2308 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2309 */
2310 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2311 perf_evlist__reset_sample_bit(evlist, ID);
2312 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002313 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002314
Namhyung Kimf15eb532012-10-05 14:02:16 +09002315 signal(SIGCHLD, sig_handler);
2316 signal(SIGINT, sig_handler);
2317
2318 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002319 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002320 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002321 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002322 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002323 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002324 }
2325 }
2326
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002327 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002328 if (err < 0)
2329 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002330
Wang Nanba504232016-02-26 09:31:54 +00002331 err = bpf__apply_obj_config();
2332 if (err) {
2333 char errbuf[BUFSIZ];
2334
2335 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2336 pr_err("ERROR: Apply config to BPF failed: %s\n",
2337 errbuf);
2338 goto out_error_open;
2339 }
2340
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002341 /*
2342 * Better not use !target__has_task() here because we need to cover the
2343 * case where no threads were specified in the command line, but a
2344 * workload was, and in that case we will fill in the thread_map when
2345 * we fork the workload in perf_evlist__prepare_workload.
2346 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002347 if (trace->filter_pids.nr > 0)
2348 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002349 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002350 err = perf_evlist__set_filter_pid(evlist, getpid());
2351
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002352 if (err < 0)
2353 goto out_error_mem;
2354
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002355 if (trace->ev_qualifier_ids.nr > 0) {
2356 err = trace__set_ev_qualifier_filter(trace);
2357 if (err < 0)
2358 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002359
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002360 pr_debug("event qualifier tracepoint filter: %s\n",
2361 trace->syscalls.events.sys_exit->filter);
2362 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002363
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002364 err = perf_evlist__apply_filters(evlist, &evsel);
2365 if (err < 0)
2366 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002367
Jiri Olsaf8850372013-11-28 17:57:22 +01002368 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002369 if (err < 0)
2370 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002371
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002372 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002373 perf_evlist__enable(evlist);
2374
Namhyung Kimf15eb532012-10-05 14:02:16 +09002375 if (forks)
2376 perf_evlist__start_workload(evlist);
2377
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002378 if (trace->opts.initial_delay) {
2379 usleep(trace->opts.initial_delay * 1000);
2380 perf_evlist__enable(evlist);
2381 }
2382
Jiri Olsae13798c2015-06-23 00:36:02 +02002383 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002384 evlist->threads->nr > 1 ||
2385 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002386again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002387 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002388
2389 for (i = 0; i < evlist->nr_mmaps; i++) {
2390 union perf_event *event;
2391
2392 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002393 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002394
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002395 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002396
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002397 err = perf_evlist__parse_sample(evlist, event, &sample);
2398 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002399 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002400 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002401 }
2402
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002403 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002404next_event:
2405 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002406
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002407 if (interrupted)
2408 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002409
2410 if (done && !draining) {
2411 perf_evlist__disable(evlist);
2412 draining = true;
2413 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002414 }
2415 }
2416
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002417 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002418 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002419
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002420 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2421 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2422 draining = true;
2423
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002424 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002425 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002426 } else {
2427 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002428 }
2429
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002430out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002431 thread__zput(trace->current);
2432
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002433 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002434
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002435 if (!err) {
2436 if (trace->summary)
2437 trace__fprintf_thread_summary(trace, trace->output);
2438
2439 if (trace->show_tool_stats) {
2440 fprintf(trace->output, "Stats:\n "
2441 " vfs_getname : %" PRIu64 "\n"
2442 " proc_getname: %" PRIu64 "\n",
2443 trace->stats.vfs_getname,
2444 trace->stats.proc_getname);
2445 }
2446 }
David Ahernbf2575c2013-10-08 21:26:53 -06002447
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002448out_delete_evlist:
2449 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002450 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002451 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002452 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002453{
2454 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002455
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002456out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002457 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002458 goto out_error;
2459
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002460out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002461 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002462 goto out_error;
2463
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002464out_error_mmap:
2465 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2466 goto out_error;
2467
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002468out_error_open:
2469 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2470
2471out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002472 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302473 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002474
2475out_error_apply_filters:
2476 fprintf(trace->output,
2477 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2478 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002479 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002480 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002481}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002482out_error_mem:
2483 fprintf(trace->output, "Not enough memory to run!\n");
2484 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002485
2486out_errno:
2487 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2488 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002489}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002490
David Ahern6810fc92013-08-28 22:29:52 -06002491static int trace__replay(struct trace *trace)
2492{
2493 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002494 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002495 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002496 struct perf_data_file file = {
2497 .path = input_name,
2498 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002499 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002500 };
David Ahern6810fc92013-08-28 22:29:52 -06002501 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002502 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002503 int err = -1;
2504
2505 trace->tool.sample = trace__process_sample;
2506 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002507 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002508 trace->tool.comm = perf_event__process_comm;
2509 trace->tool.exit = perf_event__process_exit;
2510 trace->tool.fork = perf_event__process_fork;
2511 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302512 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002513 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302514 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002515
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002516 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002517 trace->tool.ordering_requires_timestamps = true;
2518
2519 /* add tid to output */
2520 trace->multiple_threads = true;
2521
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002522 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002523 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002524 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002525
David Ahernaa07df62016-11-25 09:29:52 -07002526 if (trace->opts.target.pid)
2527 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2528
2529 if (trace->opts.target.tid)
2530 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2531
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002532 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002533 goto out;
2534
David Ahern8fb598e2013-09-28 13:13:00 -06002535 trace->host = &session->machines.host;
2536
David Ahern6810fc92013-08-28 22:29:52 -06002537 err = perf_session__set_tracepoints_handlers(session, handlers);
2538 if (err)
2539 goto out;
2540
Namhyung Kim003824e2013-11-12 15:25:00 +09002541 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2542 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002543 /* older kernels have syscalls tp versus raw_syscalls */
2544 if (evsel == NULL)
2545 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2546 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002547
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002548 if (evsel &&
2549 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2550 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002551 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2552 goto out;
2553 }
2554
2555 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2556 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002557 if (evsel == NULL)
2558 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2559 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002560 if (evsel &&
2561 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2562 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002563 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002564 goto out;
2565 }
2566
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002567 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002568 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2569 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2570 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2571 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2572 evsel->handler = trace__pgfault;
2573 }
2574
David Ahern6810fc92013-08-28 22:29:52 -06002575 setup_pager();
2576
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002577 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002578 if (err)
2579 pr_err("Failed to process events, error %d", err);
2580
David Ahernbf2575c2013-10-08 21:26:53 -06002581 else if (trace->summary)
2582 trace__fprintf_thread_summary(trace, trace->output);
2583
David Ahern6810fc92013-08-28 22:29:52 -06002584out:
2585 perf_session__delete(session);
2586
2587 return err;
2588}
2589
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002590static size_t trace__fprintf_threads_header(FILE *fp)
2591{
2592 size_t printed;
2593
Pekka Enberg99ff7152013-11-12 16:42:14 +02002594 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002595
2596 return printed;
2597}
2598
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002599DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2600 struct stats *stats;
2601 double msecs;
2602 int syscall;
2603)
2604{
2605 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2606 struct stats *stats = source->priv;
2607
2608 entry->syscall = source->i;
2609 entry->stats = stats;
2610 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2611}
2612
David Ahernbf2575c2013-10-08 21:26:53 -06002613static size_t thread__dump_stats(struct thread_trace *ttrace,
2614 struct trace *trace, FILE *fp)
2615{
David Ahernbf2575c2013-10-08 21:26:53 -06002616 size_t printed = 0;
2617 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002618 struct rb_node *nd;
2619 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002620
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002621 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002622 return 0;
2623
2624 printed += fprintf(fp, "\n");
2625
Milian Wolff834fd462015-08-06 11:24:29 +02002626 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2627 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2628 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002629
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002630 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002631 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002632 if (stats) {
2633 double min = (double)(stats->min) / NSEC_PER_MSEC;
2634 double max = (double)(stats->max) / NSEC_PER_MSEC;
2635 double avg = avg_stats(stats);
2636 double pct;
2637 u64 n = (u64) stats->n;
2638
2639 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2640 avg /= NSEC_PER_MSEC;
2641
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002642 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002643 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002644 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002645 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002646 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002647 }
David Ahernbf2575c2013-10-08 21:26:53 -06002648 }
2649
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002650 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002651 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002652
2653 return printed;
2654}
2655
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002656static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002657{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002658 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002659 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002660 double ratio;
2661
2662 if (ttrace == NULL)
2663 return 0;
2664
2665 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2666
Pekka Enberg15e65c62013-11-14 18:43:30 +02002667 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002668 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002669 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002670 if (ttrace->pfmaj)
2671 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2672 if (ttrace->pfmin)
2673 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002674 if (trace->sched)
2675 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2676 else if (fputc('\n', fp) != EOF)
2677 ++printed;
2678
David Ahernbf2575c2013-10-08 21:26:53 -06002679 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002680
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002681 return printed;
2682}
David Ahern896cbb52013-09-28 13:12:59 -06002683
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002684static unsigned long thread__nr_events(struct thread_trace *ttrace)
2685{
2686 return ttrace ? ttrace->nr_events : 0;
2687}
2688
2689DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2690 struct thread *thread;
2691)
2692{
2693 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002694}
2695
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002696static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2697{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002698 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2699 size_t printed = trace__fprintf_threads_header(fp);
2700 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002701
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002702 if (threads == NULL) {
2703 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2704 return 0;
2705 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002706
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002707 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002708 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2709
2710 resort_rb__delete(threads);
2711
2712 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002713}
2714
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002715static int trace__set_duration(const struct option *opt, const char *str,
2716 int unset __maybe_unused)
2717{
2718 struct trace *trace = opt->value;
2719
2720 trace->duration_filter = atof(str);
2721 return 0;
2722}
2723
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002724static int trace__set_filter_pids(const struct option *opt, const char *str,
2725 int unset __maybe_unused)
2726{
2727 int ret = -1;
2728 size_t i;
2729 struct trace *trace = opt->value;
2730 /*
2731 * FIXME: introduce a intarray class, plain parse csv and create a
2732 * { int nr, int entries[] } struct...
2733 */
2734 struct intlist *list = intlist__new(str);
2735
2736 if (list == NULL)
2737 return -1;
2738
2739 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2740 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2741
2742 if (trace->filter_pids.entries == NULL)
2743 goto out;
2744
2745 trace->filter_pids.entries[0] = getpid();
2746
2747 for (i = 1; i < trace->filter_pids.nr; ++i)
2748 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2749
2750 intlist__delete(list);
2751 ret = 0;
2752out:
2753 return ret;
2754}
2755
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002756static int trace__open_output(struct trace *trace, const char *filename)
2757{
2758 struct stat st;
2759
2760 if (!stat(filename, &st) && st.st_size) {
2761 char oldname[PATH_MAX];
2762
2763 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2764 unlink(oldname);
2765 rename(filename, oldname);
2766 }
2767
2768 trace->output = fopen(filename, "w");
2769
2770 return trace->output == NULL ? -errno : 0;
2771}
2772
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002773static int parse_pagefaults(const struct option *opt, const char *str,
2774 int unset __maybe_unused)
2775{
2776 int *trace_pgfaults = opt->value;
2777
2778 if (strcmp(str, "all") == 0)
2779 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2780 else if (strcmp(str, "maj") == 0)
2781 *trace_pgfaults |= TRACE_PFMAJ;
2782 else if (strcmp(str, "min") == 0)
2783 *trace_pgfaults |= TRACE_PFMIN;
2784 else
2785 return -1;
2786
2787 return 0;
2788}
2789
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002790static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2791{
2792 struct perf_evsel *evsel;
2793
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002794 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002795 evsel->handler = handler;
2796}
2797
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002798/*
2799 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2800 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2801 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2802 *
2803 * It'd be better to introduce a parse_options() variant that would return a
2804 * list with the terms it didn't match to an event...
2805 */
2806static int trace__parse_events_option(const struct option *opt, const char *str,
2807 int unset __maybe_unused)
2808{
2809 struct trace *trace = (struct trace *)opt->value;
2810 const char *s = str;
2811 char *sep = NULL, *lists[2] = { NULL, NULL, };
2812 int len = strlen(str), err = -1, list;
2813 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2814 char group_name[PATH_MAX];
2815
2816 if (strace_groups_dir == NULL)
2817 return -1;
2818
2819 if (*s == '!') {
2820 ++s;
2821 trace->not_ev_qualifier = true;
2822 }
2823
2824 while (1) {
2825 if ((sep = strchr(s, ',')) != NULL)
2826 *sep = '\0';
2827
2828 list = 0;
2829 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2830 list = 1;
2831 } else {
2832 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2833 if (access(group_name, R_OK) == 0)
2834 list = 1;
2835 }
2836
2837 if (lists[list]) {
2838 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2839 } else {
2840 lists[list] = malloc(len);
2841 if (lists[list] == NULL)
2842 goto out;
2843 strcpy(lists[list], s);
2844 }
2845
2846 if (!sep)
2847 break;
2848
2849 *sep = ',';
2850 s = sep + 1;
2851 }
2852
2853 if (lists[1] != NULL) {
2854 struct strlist_config slist_config = {
2855 .dirname = strace_groups_dir,
2856 };
2857
2858 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2859 if (trace->ev_qualifier == NULL) {
2860 fputs("Not enough memory to parse event qualifier", trace->output);
2861 goto out;
2862 }
2863
2864 if (trace__validate_ev_qualifier(trace))
2865 goto out;
2866 }
2867
2868 err = 0;
2869
2870 if (lists[0]) {
2871 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2872 "event selector. use 'perf list' to list available events",
2873 parse_events_option);
2874 err = parse_events_option(&o, lists[0], 0);
2875 }
2876out:
2877 if (sep)
2878 *sep = ',';
2879
2880 return err;
2881}
2882
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002883int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002884{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002885 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002886 "perf trace [<options>] [<command>]",
2887 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002888 "perf trace record [<options>] [<command>]",
2889 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002890 NULL
2891 };
2892 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002893 .syscalls = {
2894 . max = -1,
2895 },
2896 .opts = {
2897 .target = {
2898 .uid = UINT_MAX,
2899 .uses_mmap = true,
2900 },
2901 .user_freq = UINT_MAX,
2902 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002903 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002904 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002905 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002906 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002907 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002908 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002909 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002910 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002911 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002912 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002913 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002914 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002915 OPT_CALLBACK('e', "event", &trace, "event",
2916 "event/syscall selector. use 'perf list' to list available events",
2917 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002918 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2919 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002920 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002921 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2922 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002923 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002924 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002925 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2926 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002927 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002928 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002929 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2930 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002931 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002932 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002933 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002934 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002935 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002936 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002937 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2938 "number of mmap data pages",
2939 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002940 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002941 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002942 OPT_CALLBACK(0, "duration", &trace, "float",
2943 "show only events with duration > N.M ms",
2944 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002945 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002946 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002947 OPT_BOOLEAN('T', "time", &trace.full_time,
2948 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002949 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2950 "Show only syscall summary with statistics"),
2951 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2952 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002953 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2954 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002955 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002956 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002957 OPT_CALLBACK(0, "call-graph", &trace.opts,
2958 "record_mode[,record_size]", record_callchain_help,
2959 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002960 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2961 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002962 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2963 "Set the minimum stack depth when parsing the callchain, "
2964 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002965 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2966 "Set the maximum stack depth when parsing the callchain, "
2967 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002968 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002969 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2970 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002971 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2972 "ms to wait before starting measurement after program "
2973 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002974 OPT_END()
2975 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002976 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002977 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002978 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002979 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002980 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002981
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002982 signal(SIGSEGV, sighandler_dump_stack);
2983 signal(SIGFPE, sighandler_dump_stack);
2984
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002985 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002986 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002987
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002988 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002989 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002990 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002991 goto out;
2992 }
2993
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002994 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2995 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002996
Wang Nand7888572016-04-08 15:07:24 +00002997 err = bpf__setup_stdout(trace.evlist);
2998 if (err) {
2999 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3000 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3001 goto out;
3002 }
3003
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003004 err = -1;
3005
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003006 if (trace.trace_pgfaults) {
3007 trace.opts.sample_address = true;
3008 trace.opts.sample_time = true;
3009 }
3010
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003011 if (trace.opts.mmap_pages == UINT_MAX)
3012 mmap_pages_user_set = false;
3013
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003014 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003015 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003016 max_stack_user_set = false;
3017 }
3018
3019#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003020 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003021 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3022#endif
3023
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003024 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003025 if (!mmap_pages_user_set && geteuid() == 0)
3026 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3027
Milian Wolff566a0882016-04-08 13:34:15 +02003028 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003029 }
Milian Wolff566a0882016-04-08 13:34:15 +02003030
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003031 if (trace.evlist->nr_entries > 0)
3032 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3033
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003034 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3035 return trace__record(&trace, argc-1, &argv[1]);
3036
3037 /* summary_only implies summary option, but don't overwrite summary if set */
3038 if (trace.summary_only)
3039 trace.summary = trace.summary_only;
3040
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003041 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3042 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003043 pr_err("Please specify something to trace.\n");
3044 return -1;
3045 }
3046
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003047 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003048 pr_err("The -e option can't be used with --no-syscalls.\n");
3049 goto out;
3050 }
3051
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003052 if (output_name != NULL) {
3053 err = trace__open_output(&trace, output_name);
3054 if (err < 0) {
3055 perror("failed to create output file");
3056 goto out;
3057 }
3058 }
3059
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003060 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3061
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003062 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003063 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003064 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003065 fprintf(trace.output, "%s", bf);
3066 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003067 }
3068
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003069 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003070 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003071 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003072 fprintf(trace.output, "%s", bf);
3073 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003074 }
3075
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003076 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003077 trace.opts.target.system_wide = true;
3078
David Ahern6810fc92013-08-28 22:29:52 -06003079 if (input_name)
3080 err = trace__replay(&trace);
3081 else
3082 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003083
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003084out_close:
3085 if (output_name != NULL)
3086 fclose(trace.output);
3087out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003088 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003089}