blob: c373f9a3e4a9b736c4b0fbf54ed50abb7ca555cd [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030024#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030025#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060026#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030027#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030028#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060029#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030030#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060031#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030032#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060033#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030034#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060035#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030036#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010037#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070038#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000039#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020040#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030041#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030042#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030043#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030044#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030045
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030046#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030047#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030048#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030049#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030050#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030052#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020053#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030054#include <linux/filter.h>
55#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030060
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030061#include "sane_ctype.h"
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef O_CLOEXEC
64# define O_CLOEXEC 02000000
65#endif
66
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030067#ifndef F_LINUX_SPECIFIC_BASE
68# define F_LINUX_SPECIFIC_BASE 1024
69#endif
70
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030071struct trace {
72 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030073 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030074 struct {
75 int max;
76 struct syscall *table;
77 struct {
78 struct perf_evsel *sys_enter,
79 *sys_exit;
80 } events;
81 } syscalls;
82 struct record_opts opts;
83 struct perf_evlist *evlist;
84 struct machine *host;
85 struct thread *current;
86 u64 base_time;
87 FILE *output;
88 unsigned long nr_events;
89 struct strlist *ev_qualifier;
90 struct {
91 size_t nr;
92 int *entries;
93 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030094 struct {
95 size_t nr;
96 pid_t *entries;
97 } filter_pids;
98 double duration_filter;
99 double runtime_ms;
100 struct {
101 u64 vfs_getname,
102 proc_getname;
103 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300104 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300105 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106 bool not_ev_qualifier;
107 bool live;
108 bool full_time;
109 bool sched;
110 bool multiple_threads;
111 bool summary;
112 bool summary_only;
113 bool show_comm;
114 bool show_tool_stats;
115 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300116 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117 bool force;
118 bool vfs_getname;
119 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300120 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300122
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300123struct tp_field {
124 int offset;
125 union {
126 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
127 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
128 };
129};
130
131#define TP_UINT_FIELD(bits) \
132static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
133{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500134 u##bits value; \
135 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
136 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300137}
138
139TP_UINT_FIELD(8);
140TP_UINT_FIELD(16);
141TP_UINT_FIELD(32);
142TP_UINT_FIELD(64);
143
144#define TP_UINT_FIELD__SWAPPED(bits) \
145static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
146{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500147 u##bits value; \
148 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300149 return bswap_##bits(value);\
150}
151
152TP_UINT_FIELD__SWAPPED(16);
153TP_UINT_FIELD__SWAPPED(32);
154TP_UINT_FIELD__SWAPPED(64);
155
156static int tp_field__init_uint(struct tp_field *field,
157 struct format_field *format_field,
158 bool needs_swap)
159{
160 field->offset = format_field->offset;
161
162 switch (format_field->size) {
163 case 1:
164 field->integer = tp_field__u8;
165 break;
166 case 2:
167 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
168 break;
169 case 4:
170 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
171 break;
172 case 8:
173 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
174 break;
175 default:
176 return -1;
177 }
178
179 return 0;
180}
181
182static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
183{
184 return sample->raw_data + field->offset;
185}
186
187static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
188{
189 field->offset = format_field->offset;
190 field->pointer = tp_field__ptr;
191 return 0;
192}
193
194struct syscall_tp {
195 struct tp_field id;
196 union {
197 struct tp_field args, ret;
198 };
199};
200
201static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
202 struct tp_field *field,
203 const char *name)
204{
205 struct format_field *format_field = perf_evsel__field(evsel, name);
206
207 if (format_field == NULL)
208 return -1;
209
210 return tp_field__init_uint(field, format_field, evsel->needs_swap);
211}
212
213#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
214 ({ struct syscall_tp *sc = evsel->priv;\
215 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
216
217static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
218 struct tp_field *field,
219 const char *name)
220{
221 struct format_field *format_field = perf_evsel__field(evsel, name);
222
223 if (format_field == NULL)
224 return -1;
225
226 return tp_field__init_ptr(field, format_field);
227}
228
229#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
230 ({ struct syscall_tp *sc = evsel->priv;\
231 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
232
233static void perf_evsel__delete_priv(struct perf_evsel *evsel)
234{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300235 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300236 perf_evsel__delete(evsel);
237}
238
Namhyung Kim96695d42013-11-12 08:51:45 -0300239static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
240{
241 evsel->priv = malloc(sizeof(struct syscall_tp));
242 if (evsel->priv != NULL) {
243 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
244 goto out_delete;
245
246 evsel->handler = handler;
247 return 0;
248 }
249
250 return -ENOMEM;
251
252out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300253 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300254 return -ENOENT;
255}
256
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300257static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300258{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300259 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300260
David Ahern9aca7f12013-12-04 19:41:39 -0700261 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200262 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700263 evsel = perf_evsel__newtp("syscalls", direction);
264
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200265 if (IS_ERR(evsel))
266 return NULL;
267
268 if (perf_evsel__init_syscall_tp(evsel, handler))
269 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300270
271 return evsel;
272
273out_delete:
274 perf_evsel__delete_priv(evsel);
275 return NULL;
276}
277
278#define perf_evsel__sc_tp_uint(evsel, name, sample) \
279 ({ struct syscall_tp *fields = evsel->priv; \
280 fields->name.integer(&fields->name, sample); })
281
282#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
283 ({ struct syscall_tp *fields = evsel->priv; \
284 fields->name.pointer(&fields->name, sample); })
285
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300286size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
287{
288 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300289
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300290 if (idx < 0 || idx >= sa->nr_entries)
291 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300292
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300293 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300294}
295
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300296static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
297 const char *intfmt,
298 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300299{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300300 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300301}
302
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
307}
308
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309#define SCA_STRARRAY syscall_arg__scnprintf_strarray
310
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300311struct strarrays {
312 int nr_entries;
313 struct strarray **entries;
314};
315
316#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
317 .nr_entries = ARRAY_SIZE(array), \
318 .entries = array, \
319}
320
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300321size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
322 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300323{
324 struct strarrays *sas = arg->parm;
325 int i;
326
327 for (i = 0; i < sas->nr_entries; ++i) {
328 struct strarray *sa = sas->entries[i];
329 int idx = arg->val - sa->offset;
330
331 if (idx >= 0 && idx < sa->nr_entries) {
332 if (sa->entries[idx] == NULL)
333 break;
334 return scnprintf(bf, size, "%s", sa->entries[idx]);
335 }
336 }
337
338 return scnprintf(bf, size, "%d", arg->val);
339}
340
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300341#ifndef AT_FDCWD
342#define AT_FDCWD -100
343#endif
344
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300345static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
346 struct syscall_arg *arg)
347{
348 int fd = arg->val;
349
350 if (fd == AT_FDCWD)
351 return scnprintf(bf, size, "CWD");
352
353 return syscall_arg__scnprintf_fd(bf, size, arg);
354}
355
356#define SCA_FDAT syscall_arg__scnprintf_fd_at
357
358static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
359 struct syscall_arg *arg);
360
361#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
362
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300363size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300364{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300365 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300366}
367
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300368size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300369{
370 return scnprintf(bf, size, "%d", arg->val);
371}
372
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300373size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
374{
375 return scnprintf(bf, size, "%ld", arg->val);
376}
377
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300378static const char *bpf_cmd[] = {
379 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
380 "MAP_GET_NEXT_KEY", "PROG_LOAD",
381};
382static DEFINE_STRARRAY(bpf_cmd);
383
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300384static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
385static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300386
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300387static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
388static DEFINE_STRARRAY(itimers);
389
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300390static const char *keyctl_options[] = {
391 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
392 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
393 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
394 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
395 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
396};
397static DEFINE_STRARRAY(keyctl_options);
398
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300399static const char *whences[] = { "SET", "CUR", "END",
400#ifdef SEEK_DATA
401"DATA",
402#endif
403#ifdef SEEK_HOLE
404"HOLE",
405#endif
406};
407static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300408
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300409static const char *fcntl_cmds[] = {
410 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300411 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
412 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
413 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300414};
415static DEFINE_STRARRAY(fcntl_cmds);
416
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300417static const char *fcntl_linux_specific_cmds[] = {
418 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
419 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300420 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300421};
422
423static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
424
425static struct strarray *fcntl_cmds_arrays[] = {
426 &strarray__fcntl_cmds,
427 &strarray__fcntl_linux_specific_cmds,
428};
429
430static DEFINE_STRARRAYS(fcntl_cmds_arrays);
431
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300432static const char *rlimit_resources[] = {
433 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
434 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
435 "RTTIME",
436};
437static DEFINE_STRARRAY(rlimit_resources);
438
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300439static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
440static DEFINE_STRARRAY(sighow);
441
David Ahern4f8c1b72013-09-22 19:45:00 -0600442static const char *clockid[] = {
443 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300444 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
445 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600446};
447static DEFINE_STRARRAY(clockid);
448
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300449static const char *socket_families[] = {
450 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
451 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
452 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
453 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
454 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
455 "ALG", "NFC", "VSOCK",
456};
457static DEFINE_STRARRAY(socket_families);
458
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300459static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
460 struct syscall_arg *arg)
461{
462 size_t printed = 0;
463 int mode = arg->val;
464
465 if (mode == F_OK) /* 0 */
466 return scnprintf(bf, size, "F");
467#define P_MODE(n) \
468 if (mode & n##_OK) { \
469 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
470 mode &= ~n##_OK; \
471 }
472
473 P_MODE(R);
474 P_MODE(W);
475 P_MODE(X);
476#undef P_MODE
477
478 if (mode)
479 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
480
481 return printed;
482}
483
484#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
485
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300486static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
487 struct syscall_arg *arg);
488
489#define SCA_FILENAME syscall_arg__scnprintf_filename
490
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300491static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
492 struct syscall_arg *arg)
493{
494 int printed = 0, flags = arg->val;
495
496#define P_FLAG(n) \
497 if (flags & O_##n) { \
498 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
499 flags &= ~O_##n; \
500 }
501
502 P_FLAG(CLOEXEC);
503 P_FLAG(NONBLOCK);
504#undef P_FLAG
505
506 if (flags)
507 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
508
509 return printed;
510}
511
512#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
513
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300514#ifndef GRND_NONBLOCK
515#define GRND_NONBLOCK 0x0001
516#endif
517#ifndef GRND_RANDOM
518#define GRND_RANDOM 0x0002
519#endif
520
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300521static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
522 struct syscall_arg *arg)
523{
524 int printed = 0, flags = arg->val;
525
526#define P_FLAG(n) \
527 if (flags & GRND_##n) { \
528 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
529 flags &= ~GRND_##n; \
530 }
531
532 P_FLAG(RANDOM);
533 P_FLAG(NONBLOCK);
534#undef P_FLAG
535
536 if (flags)
537 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
538
539 return printed;
540}
541
542#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
543
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300544#define STRARRAY(name, array) \
545 { .scnprintf = SCA_STRARRAY, \
546 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300547
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300548#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300549#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300550#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300551#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300552#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300553#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300554#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300555#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300556#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300557#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300558#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300559#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300560#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300561#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300562
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300563struct syscall_arg_fmt {
564 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
565 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300566 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300567 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300568};
569
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300570static struct syscall_fmt {
571 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300572 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300573 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300574 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300575 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300576 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300577 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300578} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300579 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300580 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300581 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300582 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300583 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300584 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300585 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300586 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300587 { .name = "clone", .errpid = true, .nr_args = 5,
588 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
589 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
590 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
591 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
592 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300593 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300594 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300595 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300596 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300597 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300598 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300599 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300600 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300601 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300602 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300603 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300604 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300605 .parm = &strarrays__fcntl_cmds_arrays,
606 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300607 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300608 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300609 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300610 { .name = "fstat", .alias = "newfstat", },
611 { .name = "fstatat", .alias = "newfstatat", },
612 { .name = "futex",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300613 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300614 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300615 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300616 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300617 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300618 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300619 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300620 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300621 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300623 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300624 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300625 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300626 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300627#if defined(__i386__) || defined(__x86_64__)
628/*
629 * FIXME: Make this available to all arches.
630 */
Arnaldo Carvalho de Melo1cc47f2d2017-07-31 13:20:14 -0300631 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300632 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300633#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300634 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300635#endif
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300636 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300638 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300639 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300640 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300641 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300642 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300643 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300644 { .name = "lstat", .alias = "newlstat", },
645 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300646 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
647 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300648 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300649 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300650 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300651 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300652 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300654 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300655 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300656 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200657/* The standard mmap maps to old_mmap on s390x */
658#if defined(__s390x__)
659 .alias = "old_mmap",
660#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300661 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
662 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
663 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300664 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300665 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
666 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300667 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300668 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300669 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300670 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
671 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
672 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300673 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300674 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300675 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300676 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300677 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300678 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300679 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300680 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300681 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300683 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300684 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
685 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300686 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
688 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300689 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300690 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
691 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
692 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300693 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300694 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300695 { .name = "pkey_alloc",
696 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
697 { .name = "pkey_free",
698 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
699 { .name = "pkey_mprotect",
700 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
701 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
702 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "poll", .timeout = true, },
704 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300705 { .name = "prctl", .alias = "arch_prctl",
706 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
707 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
708 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "pread", .alias = "pread64", },
710 { .name = "preadv", .alias = "pread", },
711 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "pwrite", .alias = "pwrite64", },
714 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300715 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300716 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300717 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300718 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300719 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300720 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300721 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300722 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300723 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300724 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300725 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300726 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300727 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300728 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300729 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300730 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300731 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300732 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300733 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300734 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300735 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
736 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300737 { .name = "select", .timeout = true, },
738 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300744 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300745 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300746 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300747 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300748 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300750 .arg = { [0] = STRARRAY(family, socket_families),
751 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [0] = STRARRAY(family, socket_families),
754 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300755 { .name = "stat", .alias = "newstat", },
756 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300757 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
758 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
759 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300760 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300761 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300764 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300765 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300766 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300768 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300769 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300770 { .name = "uname", .alias = "newuname", },
771 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300772 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300773 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300774 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300775 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300776 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300777 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300778 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300779};
780
781static int syscall_fmt__cmp(const void *name, const void *fmtp)
782{
783 const struct syscall_fmt *fmt = fmtp;
784 return strcmp(name, fmt->name);
785}
786
787static struct syscall_fmt *syscall_fmt__find(const char *name)
788{
789 const int nmemb = ARRAY_SIZE(syscall_fmts);
790 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
791}
792
793struct syscall {
794 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300795 int nr_args;
796 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300797 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300798 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300799 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300800 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300801};
802
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300803/*
804 * We need to have this 'calculated' boolean because in some cases we really
805 * don't know what is the duration of a syscall, for instance, when we start
806 * a session and some threads are waiting for a syscall to finish, say 'poll',
807 * in which case all we can do is to print "( ? ) for duration and for the
808 * start timestamp.
809 */
810static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200811{
812 double duration = (double)t / NSEC_PER_MSEC;
813 size_t printed = fprintf(fp, "(");
814
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300815 if (!calculated)
816 printed += fprintf(fp, " ? ");
817 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200818 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
819 else if (duration >= 0.01)
820 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
821 else
822 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300823 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200824}
825
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300826/**
827 * filename.ptr: The filename char pointer that will be vfs_getname'd
828 * filename.entry_str_pos: Where to insert the string translated from
829 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300830 * ret_scnprintf: syscall args may set this to a different syscall return
831 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300832 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300833struct thread_trace {
834 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300835 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300836 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400837 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300838 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300839 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300840 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300841 struct {
842 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300843 short int entry_str_pos;
844 bool pending_open;
845 unsigned int namelen;
846 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300847 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300848 struct {
849 int max;
850 char **table;
851 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600852
853 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300854};
855
856static struct thread_trace *thread_trace__new(void)
857{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300858 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
859
860 if (ttrace)
861 ttrace->paths.max = -1;
862
David Ahernbf2575c2013-10-08 21:26:53 -0600863 ttrace->syscall_stats = intlist__new(NULL);
864
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300865 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300866}
867
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300868static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300869{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300870 struct thread_trace *ttrace;
871
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300872 if (thread == NULL)
873 goto fail;
874
Namhyung Kim89dceb22014-10-06 09:46:03 +0900875 if (thread__priv(thread) == NULL)
876 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300877
Namhyung Kim89dceb22014-10-06 09:46:03 +0900878 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300879 goto fail;
880
Namhyung Kim89dceb22014-10-06 09:46:03 +0900881 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300882 ++ttrace->nr_events;
883
884 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300885fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300886 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300887 "WARNING: not enough memory, dropping samples!\n");
888 return NULL;
889}
890
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300891
892void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300893 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300894{
895 struct thread_trace *ttrace = thread__priv(arg->thread);
896
897 ttrace->ret_scnprintf = ret_scnprintf;
898}
899
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400900#define TRACE_PFMAJ (1 << 0)
901#define TRACE_PFMIN (1 << 1)
902
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300903static const size_t trace__entry_str_size = 2048;
904
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300905static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300906{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900907 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908
909 if (fd > ttrace->paths.max) {
910 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
911
912 if (npath == NULL)
913 return -1;
914
915 if (ttrace->paths.max != -1) {
916 memset(npath + ttrace->paths.max + 1, 0,
917 (fd - ttrace->paths.max) * sizeof(char *));
918 } else {
919 memset(npath, 0, (fd + 1) * sizeof(char *));
920 }
921
922 ttrace->paths.table = npath;
923 ttrace->paths.max = fd;
924 }
925
926 ttrace->paths.table[fd] = strdup(pathname);
927
928 return ttrace->paths.table[fd] != NULL ? 0 : -1;
929}
930
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300931static int thread__read_fd_path(struct thread *thread, int fd)
932{
933 char linkname[PATH_MAX], pathname[PATH_MAX];
934 struct stat st;
935 int ret;
936
937 if (thread->pid_ == thread->tid) {
938 scnprintf(linkname, sizeof(linkname),
939 "/proc/%d/fd/%d", thread->pid_, fd);
940 } else {
941 scnprintf(linkname, sizeof(linkname),
942 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
943 }
944
945 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
946 return -1;
947
948 ret = readlink(linkname, pathname, sizeof(pathname));
949
950 if (ret < 0 || ret > st.st_size)
951 return -1;
952
953 pathname[ret] = '\0';
954 return trace__set_fd_pathname(thread, fd, pathname);
955}
956
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300957static const char *thread__fd_path(struct thread *thread, int fd,
958 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300959{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900960 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300961
962 if (ttrace == NULL)
963 return NULL;
964
965 if (fd < 0)
966 return NULL;
967
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300968 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300969 if (!trace->live)
970 return NULL;
971 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300972 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300973 return NULL;
974 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975
976 return ttrace->paths.table[fd];
977}
978
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -0300979size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300980{
981 int fd = arg->val;
982 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300983 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300984
985 if (path)
986 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
987
988 return printed;
989}
990
991static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
992 struct syscall_arg *arg)
993{
994 int fd = arg->val;
995 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +0900996 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300997
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300998 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
999 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001000
1001 return printed;
1002}
1003
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001004static void thread__set_filename_pos(struct thread *thread, const char *bf,
1005 unsigned long ptr)
1006{
1007 struct thread_trace *ttrace = thread__priv(thread);
1008
1009 ttrace->filename.ptr = ptr;
1010 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1011}
1012
1013static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1014 struct syscall_arg *arg)
1015{
1016 unsigned long ptr = arg->val;
1017
1018 if (!arg->trace->vfs_getname)
1019 return scnprintf(bf, size, "%#x", ptr);
1020
1021 thread__set_filename_pos(arg->thread, bf, ptr);
1022 return 0;
1023}
1024
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001025static bool trace__filter_duration(struct trace *trace, double t)
1026{
1027 return t < (trace->duration_filter * NSEC_PER_MSEC);
1028}
1029
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001030static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001031{
1032 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1033
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001034 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001035}
1036
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001037/*
1038 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1039 * using ttrace->entry_time for a thread that receives a sys_exit without
1040 * first having received a sys_enter ("poll" issued before tracing session
1041 * starts, lost sys_enter exit due to ring buffer overflow).
1042 */
1043static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1044{
1045 if (tstamp > 0)
1046 return __trace__fprintf_tstamp(trace, tstamp, fp);
1047
1048 return fprintf(fp, " ? ");
1049}
1050
Namhyung Kimf15eb532012-10-05 14:02:16 +09001051static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001052static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001053
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001054static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001055{
1056 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001057 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001058}
1059
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001060static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001061 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001062{
1063 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001064 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001065
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001066 if (trace->multiple_threads) {
1067 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001068 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001069 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001070 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001071
1072 return printed;
1073}
1074
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001075static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001076 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001077{
1078 int ret = 0;
1079
1080 switch (event->header.type) {
1081 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001082 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001083 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001084 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001085 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001086 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001087 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001088 break;
1089 }
1090
1091 return ret;
1092}
1093
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001094static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001095 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001096 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001097 struct machine *machine)
1098{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001099 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001100 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101}
1102
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001103static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1104{
1105 struct machine *machine = vmachine;
1106
1107 if (machine->kptr_restrict_warned)
1108 return NULL;
1109
1110 if (symbol_conf.kptr_restrict) {
1111 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1112 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1113 "Kernel samples will not be resolved.\n");
1114 machine->kptr_restrict_warned = true;
1115 return NULL;
1116 }
1117
1118 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1119}
1120
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1122{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001123 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001124
1125 if (err)
1126 return err;
1127
David Ahern8fb598e2013-09-28 13:13:00 -06001128 trace->host = machine__new_host();
1129 if (trace->host == NULL)
1130 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001132 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001133 return -errno;
1134
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001135 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001136 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001137 trace->opts.proc_map_timeout, 1);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001138 if (err)
1139 symbol__exit();
1140
1141 return err;
1142}
1143
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001144static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1145{
1146 int idx;
1147
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001148 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1149 nr_args = sc->fmt->nr_args;
1150
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001151 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1152 if (sc->arg_fmt == NULL)
1153 return -1;
1154
1155 for (idx = 0; idx < nr_args; ++idx) {
1156 if (sc->fmt)
1157 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1158 }
1159
1160 sc->nr_args = nr_args;
1161 return 0;
1162}
1163
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001164static int syscall__set_arg_fmts(struct syscall *sc)
1165{
1166 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001167 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001168
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001169 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001170 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1171 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001172
1173 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001174 (strcmp(field->name, "filename") == 0 ||
1175 strcmp(field->name, "path") == 0 ||
1176 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001177 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001178 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001179 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001180 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001181 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001182 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001183 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001184 else if ((strcmp(field->type, "int") == 0 ||
1185 strcmp(field->type, "unsigned int") == 0 ||
1186 strcmp(field->type, "long") == 0) &&
1187 (len = strlen(field->name)) >= 2 &&
1188 strcmp(field->name + len - 2, "fd") == 0) {
1189 /*
1190 * /sys/kernel/tracing/events/syscalls/sys_enter*
1191 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1192 * 65 int
1193 * 23 unsigned int
1194 * 7 unsigned long
1195 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001196 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001197 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001198 }
1199
1200 return 0;
1201}
1202
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001203static int trace__read_syscall_info(struct trace *trace, int id)
1204{
1205 char tp_name[128];
1206 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001207 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001208
1209 if (name == NULL)
1210 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001211
1212 if (id > trace->syscalls.max) {
1213 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1214
1215 if (nsyscalls == NULL)
1216 return -1;
1217
1218 if (trace->syscalls.max != -1) {
1219 memset(nsyscalls + trace->syscalls.max + 1, 0,
1220 (id - trace->syscalls.max) * sizeof(*sc));
1221 } else {
1222 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1223 }
1224
1225 trace->syscalls.table = nsyscalls;
1226 trace->syscalls.max = id;
1227 }
1228
1229 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001230 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001231
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001232 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001233
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001234 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001235 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001236
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001237 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001238 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001239 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001240 }
1241
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001242 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1243 return -1;
1244
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001245 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001246 return -1;
1247
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001248 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001249 /*
1250 * We need to check and discard the first variable '__syscall_nr'
1251 * or 'nr' that mean the syscall number. It is needless here.
1252 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1253 */
1254 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001255 sc->args = sc->args->next;
1256 --sc->nr_args;
1257 }
1258
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001259 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1260
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001261 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001262}
1263
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001264static int trace__validate_ev_qualifier(struct trace *trace)
1265{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001266 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001267 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001268 struct str_node *pos;
1269
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001270 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1271 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1272 sizeof(trace->ev_qualifier_ids.entries[0]));
1273
1274 if (trace->ev_qualifier_ids.entries == NULL) {
1275 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1276 trace->output);
1277 err = -EINVAL;
1278 goto out;
1279 }
1280
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001281 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001282 i = 0;
1283
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001284 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001285 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001286 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001287
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001288 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001289 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1290 if (id >= 0)
1291 goto matches;
1292
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001293 if (err == 0) {
1294 fputs("Error:\tInvalid syscall ", trace->output);
1295 err = -EINVAL;
1296 } else {
1297 fputs(", ", trace->output);
1298 }
1299
1300 fputs(sc, trace->output);
1301 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001302matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001303 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001304 if (match_next == -1)
1305 continue;
1306
1307 while (1) {
1308 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1309 if (id < 0)
1310 break;
1311 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1312 void *entries;
1313
1314 nr_allocated += 8;
1315 entries = realloc(trace->ev_qualifier_ids.entries,
1316 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1317 if (entries == NULL) {
1318 err = -ENOMEM;
1319 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1320 goto out_free;
1321 }
1322 trace->ev_qualifier_ids.entries = entries;
1323 }
1324 trace->ev_qualifier_ids.nr++;
1325 trace->ev_qualifier_ids.entries[i++] = id;
1326 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001327 }
1328
1329 if (err < 0) {
1330 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1331 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001332out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001333 zfree(&trace->ev_qualifier_ids.entries);
1334 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001335 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001336out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001337 return err;
1338}
1339
David Ahern55d43bca2015-02-19 15:00:22 -05001340/*
1341 * args is to be interpreted as a series of longs but we need to handle
1342 * 8-byte unaligned accesses. args points to raw_data within the event
1343 * and raw_data is guaranteed to be 8-byte unaligned because it is
1344 * preceded by raw_size which is a u32. So we need to copy args to a temp
1345 * variable to read it. Most notably this avoids extended load instructions
1346 * on unaligned addresses
1347 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001348unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001349{
1350 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001351 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001352
1353 memcpy(&val, p, sizeof(val));
1354 return val;
1355}
1356
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001357static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1358 struct syscall_arg *arg)
1359{
1360 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1361 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1362
1363 return scnprintf(bf, size, "arg%d: ", arg->idx);
1364}
1365
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001366static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1367 struct syscall_arg *arg, unsigned long val)
1368{
1369 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1370 arg->val = val;
1371 if (sc->arg_fmt[arg->idx].parm)
1372 arg->parm = sc->arg_fmt[arg->idx].parm;
1373 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1374 }
1375 return scnprintf(bf, size, "%ld", val);
1376}
1377
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001378static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001379 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001380 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001381{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001382 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001383 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001384 u8 bit = 1;
1385 struct syscall_arg arg = {
1386 .args = args,
1387 .idx = 0,
1388 .mask = 0,
1389 .trace = trace,
1390 .thread = thread,
1391 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001392 struct thread_trace *ttrace = thread__priv(thread);
1393
1394 /*
1395 * Things like fcntl will set this in its 'cmd' formatter to pick the
1396 * right formatter for the return value (an fd? file flags?), which is
1397 * not needed for syscalls that always return a given type, say an fd.
1398 */
1399 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001400
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001401 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001402 struct format_field *field;
1403
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001404 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001405 field = field->next, ++arg.idx, bit <<= 1) {
1406 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001407 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001408
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001409 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001410
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001411 /*
1412 * Suppress this argument if its value is zero and
1413 * and we don't have a string associated in an
1414 * strarray for it.
1415 */
David Ahern55d43bca2015-02-19 15:00:22 -05001416 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001417 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001418 (sc->arg_fmt[arg.idx].show_zero ||
1419 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001420 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1421 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001422 continue;
1423
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001424 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001425 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001426 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001427 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001428 } else if (IS_ERR(sc->tp_format)) {
1429 /*
1430 * If we managed to read the tracepoint /format file, then we
1431 * may end up not having any args, like with gettid(), so only
1432 * print the raw args when we didn't manage to read it.
1433 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001434 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001435 if (arg.mask & bit)
1436 goto next_arg;
1437 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001438 if (printed)
1439 printed += scnprintf(bf + printed, size - printed, ", ");
1440 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001441 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1442next_arg:
1443 ++arg.idx;
1444 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001445 }
1446 }
1447
1448 return printed;
1449}
1450
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001451typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001452 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001453 struct perf_sample *sample);
1454
1455static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001456 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001457{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001458
1459 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001460
1461 /*
1462 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1463 * before that, leaving at a higher verbosity level till that is
1464 * explained. Reproduced with plain ftrace with:
1465 *
1466 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1467 * grep "NR -1 " /t/trace_pipe
1468 *
1469 * After generating some load on the machine.
1470 */
1471 if (verbose > 1) {
1472 static u64 n;
1473 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1474 id, perf_evsel__name(evsel), ++n);
1475 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001476 return NULL;
1477 }
1478
1479 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1480 trace__read_syscall_info(trace, id))
1481 goto out_cant_read;
1482
1483 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1484 goto out_cant_read;
1485
1486 return &trace->syscalls.table[id];
1487
1488out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001489 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001490 fprintf(trace->output, "Problems reading syscall %d", id);
1491 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1492 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1493 fputs(" information\n", trace->output);
1494 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001495 return NULL;
1496}
1497
David Ahernbf2575c2013-10-08 21:26:53 -06001498static void thread__update_stats(struct thread_trace *ttrace,
1499 int id, struct perf_sample *sample)
1500{
1501 struct int_node *inode;
1502 struct stats *stats;
1503 u64 duration = 0;
1504
1505 inode = intlist__findnew(ttrace->syscall_stats, id);
1506 if (inode == NULL)
1507 return;
1508
1509 stats = inode->priv;
1510 if (stats == NULL) {
1511 stats = malloc(sizeof(struct stats));
1512 if (stats == NULL)
1513 return;
1514 init_stats(stats);
1515 inode->priv = stats;
1516 }
1517
1518 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1519 duration = sample->time - ttrace->entry_time;
1520
1521 update_stats(stats, duration);
1522}
1523
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001524static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1525{
1526 struct thread_trace *ttrace;
1527 u64 duration;
1528 size_t printed;
1529
1530 if (trace->current == NULL)
1531 return 0;
1532
1533 ttrace = thread__priv(trace->current);
1534
1535 if (!ttrace->entry_pending)
1536 return 0;
1537
1538 duration = sample->time - ttrace->entry_time;
1539
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001540 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001541 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1542 ttrace->entry_pending = false;
1543
1544 return printed;
1545}
1546
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001547static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001548 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001549 struct perf_sample *sample)
1550{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001551 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001552 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001553 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001554 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001555 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001556 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001557 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001558
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001559 if (sc == NULL)
1560 return -1;
1561
David Ahern8fb598e2013-09-28 13:13:00 -06001562 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001563 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001564 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001565 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001566
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001567 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001568
1569 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001570 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001571 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001572 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001573 }
1574
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001575 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001576 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001577
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001578 ttrace->entry_time = sample->time;
1579 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001580 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001581
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001582 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001583 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001584
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001585 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001586 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001587 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001588 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001589 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001590 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001591 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001592 /* See trace__vfs_getname & trace__sys_exit */
1593 ttrace->filename.pending_open = false;
1594 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001595
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001596 if (trace->current != thread) {
1597 thread__put(trace->current);
1598 trace->current = thread__get(thread);
1599 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001600 err = 0;
1601out_put:
1602 thread__put(thread);
1603 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001604}
1605
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001606static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1607 struct perf_sample *sample,
1608 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001609{
1610 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001611
1612 if (machine__resolve(trace->host, &al, sample) < 0 ||
1613 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1614 return -1;
1615
1616 return 0;
1617}
1618
1619static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1620{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001621 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001622 const unsigned int print_opts = EVSEL__PRINT_SYM |
1623 EVSEL__PRINT_DSO |
1624 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001625
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001626 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001627}
1628
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001629static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001630 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001631 struct perf_sample *sample)
1632{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001633 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001634 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001635 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001636 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001637 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001638 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001639 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001640
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001641 if (sc == NULL)
1642 return -1;
1643
David Ahern8fb598e2013-09-28 13:13:00 -06001644 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001645 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001646 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001647 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001648
David Ahernbf2575c2013-10-08 21:26:53 -06001649 if (trace->summary)
1650 thread__update_stats(ttrace, id, sample);
1651
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001652 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001653
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001654 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001655 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1656 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001657 ++trace->stats.vfs_getname;
1658 }
1659
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001660 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001661 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001662 if (trace__filter_duration(trace, duration))
1663 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001664 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001665 } else if (trace->duration_filter)
1666 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001667
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001668 if (sample->callchain) {
1669 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1670 if (callchain_ret == 0) {
1671 if (callchain_cursor.nr < trace->min_stack)
1672 goto out;
1673 callchain_ret = 1;
1674 }
1675 }
1676
David Ahernfd2eaba2013-11-12 09:31:15 -07001677 if (trace->summary_only)
1678 goto out;
1679
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001680 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001681
1682 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001683 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001684 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001685 fprintf(trace->output, " ... [");
1686 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1687 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688 }
1689
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001690 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001691 if (ret < 0)
1692 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001693signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001694 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001695 } else if (ret < 0) {
1696errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001697 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001698 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001699 *e = audit_errno_to_name(-ret);
1700
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001701 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001702 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001703 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001704 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001705 else if (ttrace->ret_scnprintf) {
1706 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001707 struct syscall_arg arg = {
1708 .val = ret,
1709 .thread = thread,
1710 .trace = trace,
1711 };
1712 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001713 ttrace->ret_scnprintf = NULL;
1714 fprintf(trace->output, ") = %s", bf);
1715 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001716 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001717 else if (sc->fmt->errpid) {
1718 struct thread *child = machine__find_thread(trace->host, ret, ret);
1719
1720 if (child != NULL) {
1721 fprintf(trace->output, ") = %ld", ret);
1722 if (child->comm_set)
1723 fprintf(trace->output, " (%s)", thread__comm_str(child));
1724 thread__put(child);
1725 }
1726 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001727 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001728
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001729 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001730
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001731 if (callchain_ret > 0)
1732 trace__fprintf_callchain(trace, sample);
1733 else if (callchain_ret < 0)
1734 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001735out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001736 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001737 err = 0;
1738out_put:
1739 thread__put(thread);
1740 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001741}
1742
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001743static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001744 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001745 struct perf_sample *sample)
1746{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001747 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1748 struct thread_trace *ttrace;
1749 size_t filename_len, entry_str_len, to_move;
1750 ssize_t remaining_space;
1751 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001752 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001753
1754 if (!thread)
1755 goto out;
1756
1757 ttrace = thread__priv(thread);
1758 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001759 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001760
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001761 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001762 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001763 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001764
1765 if (ttrace->filename.namelen < filename_len) {
1766 char *f = realloc(ttrace->filename.name, filename_len + 1);
1767
1768 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001769 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001770
1771 ttrace->filename.namelen = filename_len;
1772 ttrace->filename.name = f;
1773 }
1774
1775 strcpy(ttrace->filename.name, filename);
1776 ttrace->filename.pending_open = true;
1777
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001778 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001779 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001780
1781 entry_str_len = strlen(ttrace->entry_str);
1782 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1783 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001784 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001785
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001786 if (filename_len > (size_t)remaining_space) {
1787 filename += filename_len - remaining_space;
1788 filename_len = remaining_space;
1789 }
1790
1791 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1792 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1793 memmove(pos + filename_len, pos, to_move);
1794 memcpy(pos, filename, filename_len);
1795
1796 ttrace->filename.ptr = 0;
1797 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001798out_put:
1799 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001800out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001801 return 0;
1802}
1803
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001804static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001805 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001806 struct perf_sample *sample)
1807{
1808 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1809 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001810 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001811 sample->pid,
1812 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001813 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001814
1815 if (ttrace == NULL)
1816 goto out_dump;
1817
1818 ttrace->runtime_ms += runtime_ms;
1819 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001820out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001821 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001822 return 0;
1823
1824out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001825 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001826 evsel->name,
1827 perf_evsel__strval(evsel, sample, "comm"),
1828 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1829 runtime,
1830 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001831 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001832}
1833
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001834static int bpf_output__printer(enum binary_printer_ops op,
1835 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001836{
Wang Nan1d6c9402016-02-26 09:31:55 +00001837 unsigned char ch = (unsigned char)val;
1838
1839 switch (op) {
1840 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001841 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001842 case BINARY_PRINT_DATA_BEGIN:
1843 case BINARY_PRINT_LINE_BEGIN:
1844 case BINARY_PRINT_ADDR:
1845 case BINARY_PRINT_NUM_DATA:
1846 case BINARY_PRINT_NUM_PAD:
1847 case BINARY_PRINT_SEP:
1848 case BINARY_PRINT_CHAR_PAD:
1849 case BINARY_PRINT_LINE_END:
1850 case BINARY_PRINT_DATA_END:
1851 default:
1852 break;
1853 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001854
1855 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001856}
1857
1858static void bpf_output__fprintf(struct trace *trace,
1859 struct perf_sample *sample)
1860{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001861 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1862 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001863}
1864
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001865static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1866 union perf_event *event __maybe_unused,
1867 struct perf_sample *sample)
1868{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001869 int callchain_ret = 0;
1870
1871 if (sample->callchain) {
1872 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1873 if (callchain_ret == 0) {
1874 if (callchain_cursor.nr < trace->min_stack)
1875 goto out;
1876 callchain_ret = 1;
1877 }
1878 }
1879
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001880 trace__printf_interrupted_entry(trace, sample);
1881 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001882
1883 if (trace->trace_syscalls)
1884 fprintf(trace->output, "( ): ");
1885
1886 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001887
Wang Nan1d6c9402016-02-26 09:31:55 +00001888 if (perf_evsel__is_bpf_output(evsel)) {
1889 bpf_output__fprintf(trace, sample);
1890 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001891 event_format__fprintf(evsel->tp_format, sample->cpu,
1892 sample->raw_data, sample->raw_size,
1893 trace->output);
1894 }
1895
1896 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001897
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001898 if (callchain_ret > 0)
1899 trace__fprintf_callchain(trace, sample);
1900 else if (callchain_ret < 0)
1901 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1902out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001903 return 0;
1904}
1905
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001906static void print_location(FILE *f, struct perf_sample *sample,
1907 struct addr_location *al,
1908 bool print_dso, bool print_sym)
1909{
1910
Namhyung Kimbb963e12017-02-17 17:17:38 +09001911 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001912 fprintf(f, "%s@", al->map->dso->long_name);
1913
Namhyung Kimbb963e12017-02-17 17:17:38 +09001914 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001915 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001916 al->addr - al->sym->start);
1917 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001918 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001919 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001920 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001921}
1922
1923static int trace__pgfault(struct trace *trace,
1924 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001925 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001926 struct perf_sample *sample)
1927{
1928 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001929 struct addr_location al;
1930 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001931 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001932 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001933 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001934
1935 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001936
1937 if (sample->callchain) {
1938 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1939 if (callchain_ret == 0) {
1940 if (callchain_cursor.nr < trace->min_stack)
1941 goto out_put;
1942 callchain_ret = 1;
1943 }
1944 }
1945
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001946 ttrace = thread__trace(thread, trace->output);
1947 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001948 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001949
1950 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1951 ttrace->pfmaj++;
1952 else
1953 ttrace->pfmin++;
1954
1955 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001956 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001957
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001958 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001959 sample->ip, &al);
1960
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001961 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001962
1963 fprintf(trace->output, "%sfault [",
1964 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1965 "maj" : "min");
1966
1967 print_location(trace->output, sample, &al, false, true);
1968
1969 fprintf(trace->output, "] => ");
1970
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001971 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001972 sample->addr, &al);
1973
1974 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001975 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001976 MAP__FUNCTION, sample->addr, &al);
1977
1978 if (al.map)
1979 map_type = 'x';
1980 else
1981 map_type = '?';
1982 }
1983
1984 print_location(trace->output, sample, &al, true, false);
1985
1986 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001987
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001988 if (callchain_ret > 0)
1989 trace__fprintf_callchain(trace, sample);
1990 else if (callchain_ret < 0)
1991 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001992out:
1993 err = 0;
1994out_put:
1995 thread__put(thread);
1996 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001997}
1998
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001999static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002000 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002001 struct perf_sample *sample)
2002{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002003 /*
2004 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2005 * and don't use sample->time unconditionally, we may end up having
2006 * some other event in the future without PERF_SAMPLE_TIME for good
2007 * reason, i.e. we may not be interested in its timestamps, just in
2008 * it taking place, picking some piece of information when it
2009 * appears in our event stream (vfs_getname comes to mind).
2010 */
2011 if (trace->base_time == 0 && !trace->full_time &&
2012 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002013 trace->base_time = sample->time;
2014}
2015
David Ahern6810fc92013-08-28 22:29:52 -06002016static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002017 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002018 struct perf_sample *sample,
2019 struct perf_evsel *evsel,
2020 struct machine *machine __maybe_unused)
2021{
2022 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002023 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002024 int err = 0;
2025
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002026 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002027
David Ahernaa07df62016-11-25 09:29:52 -07002028 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2029 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002030 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002031
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002032 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002033
David Ahern31605652013-12-04 19:41:41 -07002034 if (handler) {
2035 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002036 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002037 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002038out:
2039 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002040 return err;
2041}
2042
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002043static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002044{
2045 unsigned int rec_argc, i, j;
2046 const char **rec_argv;
2047 const char * const record_args[] = {
2048 "record",
2049 "-R",
2050 "-m", "1024",
2051 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002052 };
2053
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002054 const char * const sc_args[] = { "-e", };
2055 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2056 const char * const majpf_args[] = { "-e", "major-faults" };
2057 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2058 const char * const minpf_args[] = { "-e", "minor-faults" };
2059 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2060
David Ahern9aca7f12013-12-04 19:41:39 -07002061 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002062 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2063 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002064 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2065
2066 if (rec_argv == NULL)
2067 return -ENOMEM;
2068
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002069 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002070 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002071 rec_argv[j++] = record_args[i];
2072
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002073 if (trace->trace_syscalls) {
2074 for (i = 0; i < sc_args_nr; i++)
2075 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002076
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002077 /* event string may be different for older kernels - e.g., RHEL6 */
2078 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2079 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2080 else if (is_valid_tracepoint("syscalls:sys_enter"))
2081 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2082 else {
2083 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002084 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002085 return -1;
2086 }
David Ahern9aca7f12013-12-04 19:41:39 -07002087 }
David Ahern9aca7f12013-12-04 19:41:39 -07002088
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002089 if (trace->trace_pgfaults & TRACE_PFMAJ)
2090 for (i = 0; i < majpf_args_nr; i++)
2091 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002092
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002093 if (trace->trace_pgfaults & TRACE_PFMIN)
2094 for (i = 0; i < minpf_args_nr; i++)
2095 rec_argv[j++] = minpf_args[i];
2096
2097 for (i = 0; i < (unsigned int)argc; i++)
2098 rec_argv[j++] = argv[i];
2099
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002100 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002101}
2102
David Ahernbf2575c2013-10-08 21:26:53 -06002103static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2104
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002105static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002106{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002107 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002108
2109 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002110 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002111
2112 if (perf_evsel__field(evsel, "pathname") == NULL) {
2113 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002114 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002115 }
2116
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002117 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002118 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002119 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002120}
2121
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002122static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002123{
2124 struct perf_evsel *evsel;
2125 struct perf_event_attr attr = {
2126 .type = PERF_TYPE_SOFTWARE,
2127 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002128 };
2129
2130 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002131 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002132
2133 event_attr_init(&attr);
2134
2135 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002136 if (evsel)
2137 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002138
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002139 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002140}
2141
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002142static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2143{
2144 const u32 type = event->header.type;
2145 struct perf_evsel *evsel;
2146
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002147 if (type != PERF_RECORD_SAMPLE) {
2148 trace__process_event(trace, trace->host, event, sample);
2149 return;
2150 }
2151
2152 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2153 if (evsel == NULL) {
2154 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2155 return;
2156 }
2157
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002158 trace__set_base_time(trace, evsel, sample);
2159
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002160 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2161 sample->raw_data == NULL) {
2162 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2163 perf_evsel__name(evsel), sample->tid,
2164 sample->cpu, sample->raw_size);
2165 } else {
2166 tracepoint_handler handler = evsel->handler;
2167 handler(trace, evsel, event, sample);
2168 }
2169}
2170
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002171static int trace__add_syscall_newtp(struct trace *trace)
2172{
2173 int ret = -1;
2174 struct perf_evlist *evlist = trace->evlist;
2175 struct perf_evsel *sys_enter, *sys_exit;
2176
2177 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2178 if (sys_enter == NULL)
2179 goto out;
2180
2181 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2182 goto out_delete_sys_enter;
2183
2184 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2185 if (sys_exit == NULL)
2186 goto out_delete_sys_enter;
2187
2188 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2189 goto out_delete_sys_exit;
2190
2191 perf_evlist__add(evlist, sys_enter);
2192 perf_evlist__add(evlist, sys_exit);
2193
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002194 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002195 /*
2196 * We're interested only in the user space callchain
2197 * leading to the syscall, allow overriding that for
2198 * debugging reasons using --kernel_syscall_callchains
2199 */
2200 sys_exit->attr.exclude_callchain_kernel = 1;
2201 }
2202
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002203 trace->syscalls.events.sys_enter = sys_enter;
2204 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002205
2206 ret = 0;
2207out:
2208 return ret;
2209
2210out_delete_sys_exit:
2211 perf_evsel__delete_priv(sys_exit);
2212out_delete_sys_enter:
2213 perf_evsel__delete_priv(sys_enter);
2214 goto out;
2215}
2216
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002217static int trace__set_ev_qualifier_filter(struct trace *trace)
2218{
2219 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002220 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002221 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2222 trace->ev_qualifier_ids.nr,
2223 trace->ev_qualifier_ids.entries);
2224
2225 if (filter == NULL)
2226 goto out_enomem;
2227
Mathieu Poirier3541c032016-09-16 08:44:04 -06002228 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2229 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002230 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002231 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002232 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002233
2234 free(filter);
2235out:
2236 return err;
2237out_enomem:
2238 errno = ENOMEM;
2239 goto out;
2240}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002241
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002242static int trace__set_filter_loop_pids(struct trace *trace)
2243{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002244 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002245 pid_t pids[32] = {
2246 getpid(),
2247 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002248 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2249
2250 while (thread && nr < ARRAY_SIZE(pids)) {
2251 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2252
2253 if (parent == NULL)
2254 break;
2255
2256 if (!strcmp(thread__comm_str(parent), "sshd")) {
2257 pids[nr++] = parent->tid;
2258 break;
2259 }
2260 thread = parent;
2261 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002262
2263 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2264}
2265
Namhyung Kimf15eb532012-10-05 14:02:16 +09002266static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002267{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002268 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002269 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002270 int err = -1, i;
2271 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002272 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002273 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002274
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002275 trace->live = true;
2276
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002277 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002278 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002279
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002280 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002281 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002282
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002283 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2284 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2285 if (pgfault_maj == NULL)
2286 goto out_error_mem;
2287 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002288 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002289
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002290 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2291 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2292 if (pgfault_min == NULL)
2293 goto out_error_mem;
2294 perf_evlist__add(evlist, pgfault_min);
2295 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002296
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002297 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002298 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2299 trace__sched_stat_runtime))
2300 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002301
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002302 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2303 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002304 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002305 goto out_delete_evlist;
2306 }
2307
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002308 err = trace__symbols_init(trace, evlist);
2309 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002310 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002311 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002312 }
2313
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002314 perf_evlist__config(evlist, &trace->opts, NULL);
2315
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002316 if (callchain_param.enabled) {
2317 bool use_identifier = false;
2318
2319 if (trace->syscalls.events.sys_exit) {
2320 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2321 &trace->opts, &callchain_param);
2322 use_identifier = true;
2323 }
2324
2325 if (pgfault_maj) {
2326 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2327 use_identifier = true;
2328 }
2329
2330 if (pgfault_min) {
2331 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2332 use_identifier = true;
2333 }
2334
2335 if (use_identifier) {
2336 /*
2337 * Now we have evsels with different sample_ids, use
2338 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2339 * from a fixed position in each ring buffer record.
2340 *
2341 * As of this the changeset introducing this comment, this
2342 * isn't strictly needed, as the fields that can come before
2343 * PERF_SAMPLE_ID are all used, but we'll probably disable
2344 * some of those for things like copying the payload of
2345 * pointer syscall arguments, and for vfs_getname we don't
2346 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2347 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2348 */
2349 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2350 perf_evlist__reset_sample_bit(evlist, ID);
2351 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002352 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002353
Namhyung Kimf15eb532012-10-05 14:02:16 +09002354 signal(SIGCHLD, sig_handler);
2355 signal(SIGINT, sig_handler);
2356
2357 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002358 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002359 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002360 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002361 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002362 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002363 }
2364 }
2365
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002366 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002367 if (err < 0)
2368 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002369
Wang Nanba504232016-02-26 09:31:54 +00002370 err = bpf__apply_obj_config();
2371 if (err) {
2372 char errbuf[BUFSIZ];
2373
2374 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2375 pr_err("ERROR: Apply config to BPF failed: %s\n",
2376 errbuf);
2377 goto out_error_open;
2378 }
2379
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002380 /*
2381 * Better not use !target__has_task() here because we need to cover the
2382 * case where no threads were specified in the command line, but a
2383 * workload was, and in that case we will fill in the thread_map when
2384 * we fork the workload in perf_evlist__prepare_workload.
2385 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002386 if (trace->filter_pids.nr > 0)
2387 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002388 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002389 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002390
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002391 if (err < 0)
2392 goto out_error_mem;
2393
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002394 if (trace->ev_qualifier_ids.nr > 0) {
2395 err = trace__set_ev_qualifier_filter(trace);
2396 if (err < 0)
2397 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002398
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002399 pr_debug("event qualifier tracepoint filter: %s\n",
2400 trace->syscalls.events.sys_exit->filter);
2401 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002402
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002403 err = perf_evlist__apply_filters(evlist, &evsel);
2404 if (err < 0)
2405 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002406
Jiri Olsaf8850372013-11-28 17:57:22 +01002407 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002408 if (err < 0)
2409 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002410
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002411 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002412 perf_evlist__enable(evlist);
2413
Namhyung Kimf15eb532012-10-05 14:02:16 +09002414 if (forks)
2415 perf_evlist__start_workload(evlist);
2416
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002417 if (trace->opts.initial_delay) {
2418 usleep(trace->opts.initial_delay * 1000);
2419 perf_evlist__enable(evlist);
2420 }
2421
Jiri Olsae13798c2015-06-23 00:36:02 +02002422 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002423 evlist->threads->nr > 1 ||
2424 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002425again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002426 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002427
2428 for (i = 0; i < evlist->nr_mmaps; i++) {
2429 union perf_event *event;
2430
2431 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002432 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002433
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002434 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002435
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002436 err = perf_evlist__parse_sample(evlist, event, &sample);
2437 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002438 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002439 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002440 }
2441
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002442 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002443next_event:
2444 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002445
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002446 if (interrupted)
2447 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002448
2449 if (done && !draining) {
2450 perf_evlist__disable(evlist);
2451 draining = true;
2452 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002453 }
2454 }
2455
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002456 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002457 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002458
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002459 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2460 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2461 draining = true;
2462
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002463 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002464 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002465 } else {
2466 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002467 }
2468
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002469out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002470 thread__zput(trace->current);
2471
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002472 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002473
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002474 if (!err) {
2475 if (trace->summary)
2476 trace__fprintf_thread_summary(trace, trace->output);
2477
2478 if (trace->show_tool_stats) {
2479 fprintf(trace->output, "Stats:\n "
2480 " vfs_getname : %" PRIu64 "\n"
2481 " proc_getname: %" PRIu64 "\n",
2482 trace->stats.vfs_getname,
2483 trace->stats.proc_getname);
2484 }
2485 }
David Ahernbf2575c2013-10-08 21:26:53 -06002486
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002487out_delete_evlist:
2488 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002489 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002490 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002491 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002492{
2493 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002494
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002495out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002496 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002497 goto out_error;
2498
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002499out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002500 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002501 goto out_error;
2502
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002503out_error_mmap:
2504 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2505 goto out_error;
2506
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002507out_error_open:
2508 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2509
2510out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002511 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302512 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002513
2514out_error_apply_filters:
2515 fprintf(trace->output,
2516 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2517 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002518 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002519 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002520}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002521out_error_mem:
2522 fprintf(trace->output, "Not enough memory to run!\n");
2523 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002524
2525out_errno:
2526 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2527 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002528}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002529
David Ahern6810fc92013-08-28 22:29:52 -06002530static int trace__replay(struct trace *trace)
2531{
2532 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002533 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002534 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002535 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002536 .file = {
2537 .path = input_name,
2538 },
2539 .mode = PERF_DATA_MODE_READ,
2540 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002541 };
David Ahern6810fc92013-08-28 22:29:52 -06002542 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002543 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002544 int err = -1;
2545
2546 trace->tool.sample = trace__process_sample;
2547 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002548 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002549 trace->tool.comm = perf_event__process_comm;
2550 trace->tool.exit = perf_event__process_exit;
2551 trace->tool.fork = perf_event__process_fork;
2552 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302553 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002554 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302555 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002556
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002557 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002558 trace->tool.ordering_requires_timestamps = true;
2559
2560 /* add tid to output */
2561 trace->multiple_threads = true;
2562
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002563 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002564 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002565 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002566
David Ahernaa07df62016-11-25 09:29:52 -07002567 if (trace->opts.target.pid)
2568 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2569
2570 if (trace->opts.target.tid)
2571 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2572
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002573 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002574 goto out;
2575
David Ahern8fb598e2013-09-28 13:13:00 -06002576 trace->host = &session->machines.host;
2577
David Ahern6810fc92013-08-28 22:29:52 -06002578 err = perf_session__set_tracepoints_handlers(session, handlers);
2579 if (err)
2580 goto out;
2581
Namhyung Kim003824e2013-11-12 15:25:00 +09002582 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2583 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002584 /* older kernels have syscalls tp versus raw_syscalls */
2585 if (evsel == NULL)
2586 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2587 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002588
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002589 if (evsel &&
2590 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2591 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002592 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2593 goto out;
2594 }
2595
2596 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2597 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002598 if (evsel == NULL)
2599 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2600 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002601 if (evsel &&
2602 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2603 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002604 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002605 goto out;
2606 }
2607
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002608 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002609 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2610 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2611 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2612 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2613 evsel->handler = trace__pgfault;
2614 }
2615
David Ahern6810fc92013-08-28 22:29:52 -06002616 setup_pager();
2617
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002618 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002619 if (err)
2620 pr_err("Failed to process events, error %d", err);
2621
David Ahernbf2575c2013-10-08 21:26:53 -06002622 else if (trace->summary)
2623 trace__fprintf_thread_summary(trace, trace->output);
2624
David Ahern6810fc92013-08-28 22:29:52 -06002625out:
2626 perf_session__delete(session);
2627
2628 return err;
2629}
2630
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002631static size_t trace__fprintf_threads_header(FILE *fp)
2632{
2633 size_t printed;
2634
Pekka Enberg99ff7152013-11-12 16:42:14 +02002635 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002636
2637 return printed;
2638}
2639
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002640DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2641 struct stats *stats;
2642 double msecs;
2643 int syscall;
2644)
2645{
2646 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2647 struct stats *stats = source->priv;
2648
2649 entry->syscall = source->i;
2650 entry->stats = stats;
2651 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2652}
2653
David Ahernbf2575c2013-10-08 21:26:53 -06002654static size_t thread__dump_stats(struct thread_trace *ttrace,
2655 struct trace *trace, FILE *fp)
2656{
David Ahernbf2575c2013-10-08 21:26:53 -06002657 size_t printed = 0;
2658 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002659 struct rb_node *nd;
2660 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002661
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002662 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002663 return 0;
2664
2665 printed += fprintf(fp, "\n");
2666
Milian Wolff834fd462015-08-06 11:24:29 +02002667 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2668 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2669 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002670
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002671 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002672 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002673 if (stats) {
2674 double min = (double)(stats->min) / NSEC_PER_MSEC;
2675 double max = (double)(stats->max) / NSEC_PER_MSEC;
2676 double avg = avg_stats(stats);
2677 double pct;
2678 u64 n = (u64) stats->n;
2679
2680 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2681 avg /= NSEC_PER_MSEC;
2682
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002683 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002684 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002685 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002686 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002687 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002688 }
David Ahernbf2575c2013-10-08 21:26:53 -06002689 }
2690
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002691 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002692 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002693
2694 return printed;
2695}
2696
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002697static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002698{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002699 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002700 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002701 double ratio;
2702
2703 if (ttrace == NULL)
2704 return 0;
2705
2706 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2707
Pekka Enberg15e65c62013-11-14 18:43:30 +02002708 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002709 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002710 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002711 if (ttrace->pfmaj)
2712 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2713 if (ttrace->pfmin)
2714 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002715 if (trace->sched)
2716 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2717 else if (fputc('\n', fp) != EOF)
2718 ++printed;
2719
David Ahernbf2575c2013-10-08 21:26:53 -06002720 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002721
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002722 return printed;
2723}
David Ahern896cbb52013-09-28 13:12:59 -06002724
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002725static unsigned long thread__nr_events(struct thread_trace *ttrace)
2726{
2727 return ttrace ? ttrace->nr_events : 0;
2728}
2729
2730DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2731 struct thread *thread;
2732)
2733{
2734 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002735}
2736
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002737static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2738{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002739 size_t printed = trace__fprintf_threads_header(fp);
2740 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002741 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002742
Kan Liang91e467b2017-09-10 19:23:14 -07002743 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2744 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2745
2746 if (threads == NULL) {
2747 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2748 return 0;
2749 }
2750
2751 resort_rb__for_each_entry(nd, threads)
2752 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2753
2754 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002755 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002756 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002757}
2758
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002759static int trace__set_duration(const struct option *opt, const char *str,
2760 int unset __maybe_unused)
2761{
2762 struct trace *trace = opt->value;
2763
2764 trace->duration_filter = atof(str);
2765 return 0;
2766}
2767
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002768static int trace__set_filter_pids(const struct option *opt, const char *str,
2769 int unset __maybe_unused)
2770{
2771 int ret = -1;
2772 size_t i;
2773 struct trace *trace = opt->value;
2774 /*
2775 * FIXME: introduce a intarray class, plain parse csv and create a
2776 * { int nr, int entries[] } struct...
2777 */
2778 struct intlist *list = intlist__new(str);
2779
2780 if (list == NULL)
2781 return -1;
2782
2783 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2784 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2785
2786 if (trace->filter_pids.entries == NULL)
2787 goto out;
2788
2789 trace->filter_pids.entries[0] = getpid();
2790
2791 for (i = 1; i < trace->filter_pids.nr; ++i)
2792 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2793
2794 intlist__delete(list);
2795 ret = 0;
2796out:
2797 return ret;
2798}
2799
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002800static int trace__open_output(struct trace *trace, const char *filename)
2801{
2802 struct stat st;
2803
2804 if (!stat(filename, &st) && st.st_size) {
2805 char oldname[PATH_MAX];
2806
2807 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2808 unlink(oldname);
2809 rename(filename, oldname);
2810 }
2811
2812 trace->output = fopen(filename, "w");
2813
2814 return trace->output == NULL ? -errno : 0;
2815}
2816
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002817static int parse_pagefaults(const struct option *opt, const char *str,
2818 int unset __maybe_unused)
2819{
2820 int *trace_pgfaults = opt->value;
2821
2822 if (strcmp(str, "all") == 0)
2823 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2824 else if (strcmp(str, "maj") == 0)
2825 *trace_pgfaults |= TRACE_PFMAJ;
2826 else if (strcmp(str, "min") == 0)
2827 *trace_pgfaults |= TRACE_PFMIN;
2828 else
2829 return -1;
2830
2831 return 0;
2832}
2833
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002834static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2835{
2836 struct perf_evsel *evsel;
2837
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002838 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002839 evsel->handler = handler;
2840}
2841
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002842/*
2843 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2844 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2845 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2846 *
2847 * It'd be better to introduce a parse_options() variant that would return a
2848 * list with the terms it didn't match to an event...
2849 */
2850static int trace__parse_events_option(const struct option *opt, const char *str,
2851 int unset __maybe_unused)
2852{
2853 struct trace *trace = (struct trace *)opt->value;
2854 const char *s = str;
2855 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002856 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002857 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2858 char group_name[PATH_MAX];
2859
2860 if (strace_groups_dir == NULL)
2861 return -1;
2862
2863 if (*s == '!') {
2864 ++s;
2865 trace->not_ev_qualifier = true;
2866 }
2867
2868 while (1) {
2869 if ((sep = strchr(s, ',')) != NULL)
2870 *sep = '\0';
2871
2872 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002873 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
2874 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002875 list = 1;
2876 } else {
2877 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2878 if (access(group_name, R_OK) == 0)
2879 list = 1;
2880 }
2881
2882 if (lists[list]) {
2883 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2884 } else {
2885 lists[list] = malloc(len);
2886 if (lists[list] == NULL)
2887 goto out;
2888 strcpy(lists[list], s);
2889 }
2890
2891 if (!sep)
2892 break;
2893
2894 *sep = ',';
2895 s = sep + 1;
2896 }
2897
2898 if (lists[1] != NULL) {
2899 struct strlist_config slist_config = {
2900 .dirname = strace_groups_dir,
2901 };
2902
2903 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2904 if (trace->ev_qualifier == NULL) {
2905 fputs("Not enough memory to parse event qualifier", trace->output);
2906 goto out;
2907 }
2908
2909 if (trace__validate_ev_qualifier(trace))
2910 goto out;
2911 }
2912
2913 err = 0;
2914
2915 if (lists[0]) {
2916 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2917 "event selector. use 'perf list' to list available events",
2918 parse_events_option);
2919 err = parse_events_option(&o, lists[0], 0);
2920 }
2921out:
2922 if (sep)
2923 *sep = ',';
2924
2925 return err;
2926}
2927
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002928int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002929{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002930 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002931 "perf trace [<options>] [<command>]",
2932 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002933 "perf trace record [<options>] [<command>]",
2934 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002935 NULL
2936 };
2937 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002938 .syscalls = {
2939 . max = -1,
2940 },
2941 .opts = {
2942 .target = {
2943 .uid = UINT_MAX,
2944 .uses_mmap = true,
2945 },
2946 .user_freq = UINT_MAX,
2947 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002948 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002949 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002950 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002951 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002952 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002953 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002954 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002955 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002956 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002957 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002958 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002959 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002960 OPT_CALLBACK('e', "event", &trace, "event",
2961 "event/syscall selector. use 'perf list' to list available events",
2962 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002963 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2964 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002965 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002966 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2967 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002968 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002969 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002970 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2971 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002972 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002973 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002974 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2975 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002976 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002977 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002978 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002979 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002980 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002981 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002982 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2983 "number of mmap data pages",
2984 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002985 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002986 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002987 OPT_CALLBACK(0, "duration", &trace, "float",
2988 "show only events with duration > N.M ms",
2989 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002990 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002991 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002992 OPT_BOOLEAN('T', "time", &trace.full_time,
2993 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002994 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2995 "Show only syscall summary with statistics"),
2996 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2997 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002998 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2999 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003000 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003001 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003002 OPT_CALLBACK(0, "call-graph", &trace.opts,
3003 "record_mode[,record_size]", record_callchain_help,
3004 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003005 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3006 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003007 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3008 "Set the minimum stack depth when parsing the callchain, "
3009 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003010 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3011 "Set the maximum stack depth when parsing the callchain, "
3012 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003013 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04003014 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3015 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003016 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3017 "ms to wait before starting measurement after program "
3018 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003019 OPT_END()
3020 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003021 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003022 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003023 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003024 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003025 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003026
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003027 signal(SIGSEGV, sighandler_dump_stack);
3028 signal(SIGFPE, sighandler_dump_stack);
3029
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003030 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003031 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003032
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003033 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003034 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003035 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003036 goto out;
3037 }
3038
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003039 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3040 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003041
Wang Nand7888572016-04-08 15:07:24 +00003042 err = bpf__setup_stdout(trace.evlist);
3043 if (err) {
3044 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3045 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3046 goto out;
3047 }
3048
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003049 err = -1;
3050
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003051 if (trace.trace_pgfaults) {
3052 trace.opts.sample_address = true;
3053 trace.opts.sample_time = true;
3054 }
3055
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003056 if (trace.opts.mmap_pages == UINT_MAX)
3057 mmap_pages_user_set = false;
3058
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003059 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003060 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003061 max_stack_user_set = false;
3062 }
3063
3064#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003065 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003066 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3067#endif
3068
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003069 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003070 if (!mmap_pages_user_set && geteuid() == 0)
3071 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3072
Milian Wolff566a0882016-04-08 13:34:15 +02003073 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003074 }
Milian Wolff566a0882016-04-08 13:34:15 +02003075
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003076 if (trace.evlist->nr_entries > 0)
3077 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3078
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003079 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3080 return trace__record(&trace, argc-1, &argv[1]);
3081
3082 /* summary_only implies summary option, but don't overwrite summary if set */
3083 if (trace.summary_only)
3084 trace.summary = trace.summary_only;
3085
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003086 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3087 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003088 pr_err("Please specify something to trace.\n");
3089 return -1;
3090 }
3091
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003092 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003093 pr_err("The -e option can't be used with --no-syscalls.\n");
3094 goto out;
3095 }
3096
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003097 if (output_name != NULL) {
3098 err = trace__open_output(&trace, output_name);
3099 if (err < 0) {
3100 perror("failed to create output file");
3101 goto out;
3102 }
3103 }
3104
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003105 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3106
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003107 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003108 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003109 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003110 fprintf(trace.output, "%s", bf);
3111 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003112 }
3113
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003114 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003115 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003116 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003117 fprintf(trace.output, "%s", bf);
3118 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003119 }
3120
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003121 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003122 trace.opts.target.system_wide = true;
3123
David Ahern6810fc92013-08-28 22:29:52 -06003124 if (input_name)
3125 err = trace__replay(&trace);
3126 else
3127 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003128
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003129out_close:
3130 if (output_name != NULL)
3131 fclose(trace.output);
3132out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003133 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003134}