blob: 9e171401b664ba00b90b3b0943212a8eca97a674 [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 Melo1f115cb2013-09-03 15:50:28 -0300286struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300287 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300288 int nr_entries;
289 const char **entries;
290};
291
292#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300297#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
298 .offset = off, \
299 .nr_entries = ARRAY_SIZE(array), \
300 .entries = array, \
301}
302
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
304 const char *intfmt,
305 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300307 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300308 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309
310 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300311 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300312
313 return scnprintf(bf, size, "%s", sa->entries[idx]);
314}
315
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300316static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
317 struct syscall_arg *arg)
318{
319 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
320}
321
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300322#define SCA_STRARRAY syscall_arg__scnprintf_strarray
323
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300324struct strarrays {
325 int nr_entries;
326 struct strarray **entries;
327};
328
329#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
330 .nr_entries = ARRAY_SIZE(array), \
331 .entries = array, \
332}
333
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300334size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
335 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300336{
337 struct strarrays *sas = arg->parm;
338 int i;
339
340 for (i = 0; i < sas->nr_entries; ++i) {
341 struct strarray *sa = sas->entries[i];
342 int idx = arg->val - sa->offset;
343
344 if (idx >= 0 && idx < sa->nr_entries) {
345 if (sa->entries[idx] == NULL)
346 break;
347 return scnprintf(bf, size, "%s", sa->entries[idx]);
348 }
349 }
350
351 return scnprintf(bf, size, "%d", arg->val);
352}
353
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300354#if defined(__i386__) || defined(__x86_64__)
355/*
356 * FIXME: Make this available to all arches as soon as the ioctl beautifier
357 * gets rewritten to support all arches.
358 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300359static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
360 struct syscall_arg *arg)
361{
362 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
363}
364
365#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300366#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300367
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300368static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
369 struct syscall_arg *arg);
370
371#define SCA_FD syscall_arg__scnprintf_fd
372
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300373#ifndef AT_FDCWD
374#define AT_FDCWD -100
375#endif
376
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300377static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
378 struct syscall_arg *arg)
379{
380 int fd = arg->val;
381
382 if (fd == AT_FDCWD)
383 return scnprintf(bf, size, "CWD");
384
385 return syscall_arg__scnprintf_fd(bf, size, arg);
386}
387
388#define SCA_FDAT syscall_arg__scnprintf_fd_at
389
390static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
391 struct syscall_arg *arg);
392
393#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
394
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300395size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300396{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300397 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300398}
399
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300400size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300401{
402 return scnprintf(bf, size, "%d", arg->val);
403}
404
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300405static const char *bpf_cmd[] = {
406 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
407 "MAP_GET_NEXT_KEY", "PROG_LOAD",
408};
409static DEFINE_STRARRAY(bpf_cmd);
410
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300411static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
412static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300413
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300414static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
415static DEFINE_STRARRAY(itimers);
416
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300417static const char *keyctl_options[] = {
418 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
419 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
420 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
421 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
422 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
423};
424static DEFINE_STRARRAY(keyctl_options);
425
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300426static const char *whences[] = { "SET", "CUR", "END",
427#ifdef SEEK_DATA
428"DATA",
429#endif
430#ifdef SEEK_HOLE
431"HOLE",
432#endif
433};
434static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300435
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300436static const char *fcntl_cmds[] = {
437 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300438 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
439 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
440 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300441};
442static DEFINE_STRARRAY(fcntl_cmds);
443
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300444static const char *fcntl_linux_specific_cmds[] = {
445 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
446 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
447};
448
449static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
450
451static struct strarray *fcntl_cmds_arrays[] = {
452 &strarray__fcntl_cmds,
453 &strarray__fcntl_linux_specific_cmds,
454};
455
456static DEFINE_STRARRAYS(fcntl_cmds_arrays);
457
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300458static const char *rlimit_resources[] = {
459 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
460 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
461 "RTTIME",
462};
463static DEFINE_STRARRAY(rlimit_resources);
464
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300465static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
466static DEFINE_STRARRAY(sighow);
467
David Ahern4f8c1b72013-09-22 19:45:00 -0600468static const char *clockid[] = {
469 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300470 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
471 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600472};
473static DEFINE_STRARRAY(clockid);
474
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300475static const char *socket_families[] = {
476 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
477 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
478 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
479 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
480 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
481 "ALG", "NFC", "VSOCK",
482};
483static DEFINE_STRARRAY(socket_families);
484
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300485static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
486 struct syscall_arg *arg)
487{
488 size_t printed = 0;
489 int mode = arg->val;
490
491 if (mode == F_OK) /* 0 */
492 return scnprintf(bf, size, "F");
493#define P_MODE(n) \
494 if (mode & n##_OK) { \
495 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
496 mode &= ~n##_OK; \
497 }
498
499 P_MODE(R);
500 P_MODE(W);
501 P_MODE(X);
502#undef P_MODE
503
504 if (mode)
505 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
506
507 return printed;
508}
509
510#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
511
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300512static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
513 struct syscall_arg *arg);
514
515#define SCA_FILENAME syscall_arg__scnprintf_filename
516
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300517static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
518 struct syscall_arg *arg)
519{
520 int printed = 0, flags = arg->val;
521
522#define P_FLAG(n) \
523 if (flags & O_##n) { \
524 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
525 flags &= ~O_##n; \
526 }
527
528 P_FLAG(CLOEXEC);
529 P_FLAG(NONBLOCK);
530#undef P_FLAG
531
532 if (flags)
533 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
534
535 return printed;
536}
537
538#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
539
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300540#if defined(__i386__) || defined(__x86_64__)
541/*
542 * FIXME: Make this available to all arches.
543 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300544#define TCGETS 0x5401
545
546static const char *tioctls[] = {
547 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
548 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
549 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
550 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
551 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
552 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
553 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
554 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
555 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
556 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
557 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
558 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
559 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
560 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
561 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
562};
563
564static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300565#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300566
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300567#ifndef GRND_NONBLOCK
568#define GRND_NONBLOCK 0x0001
569#endif
570#ifndef GRND_RANDOM
571#define GRND_RANDOM 0x0002
572#endif
573
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300574static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
575 struct syscall_arg *arg)
576{
577 int printed = 0, flags = arg->val;
578
579#define P_FLAG(n) \
580 if (flags & GRND_##n) { \
581 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
582 flags &= ~GRND_##n; \
583 }
584
585 P_FLAG(RANDOM);
586 P_FLAG(NONBLOCK);
587#undef P_FLAG
588
589 if (flags)
590 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
591
592 return printed;
593}
594
595#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
596
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300597#define STRARRAY(arg, name, array) \
598 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
599 .arg_parm = { [arg] = &strarray__##array, }
600
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300601#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300602#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300603#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300604#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300605#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300606#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300607#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300608#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300609#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300610#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300611#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300612#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300613#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300614#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300615
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300616static struct syscall_fmt {
617 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300618 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300619 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300620 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300621 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300622 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300623 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300624 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300625} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300626 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300627 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300628 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300629 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300630 { .name = "brk", .hexret = true,
631 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300632 { .name = "chdir", .errmsg = true, },
633 { .name = "chmod", .errmsg = true, },
634 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600635 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300636 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300637 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300638 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300639 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300640 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300641 { .name = "dup", .errmsg = true, },
642 { .name = "dup2", .errmsg = true, },
643 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300644 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300645 { .name = "eventfd2", .errmsg = true,
646 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300647 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300648 { .name = "fadvise64", .errmsg = true, },
649 { .name = "fallocate", .errmsg = true, },
650 { .name = "fchdir", .errmsg = true, },
651 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300652 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300653 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300654 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300655 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300656 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300657 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melo9cb7cf82017-07-14 09:44:50 -0300658 .arg_scnprintf = { [1] = SCA_FCNTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300659 .arg_parm = { [1] = &strarrays__fcntl_cmds_arrays, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300660 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300661 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300662 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
663 { .name = "fsetxattr", .errmsg = true, },
664 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300665 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300666 { .name = "fstatfs", .errmsg = true, },
667 { .name = "fsync", .errmsg = true, },
668 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300669 { .name = "futex", .errmsg = true,
670 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300671 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300672 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300673 { .name = "getdents", .errmsg = true, },
674 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300675 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300676 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300677 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300678 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300679 { .name = "getrandom", .errmsg = true,
680 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300681 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300682 { .name = "getxattr", .errmsg = true, },
683 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300684 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300685 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300686#if defined(__i386__) || defined(__x86_64__)
687/*
688 * FIXME: Make this available to all arches.
689 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300690 [1] = SCA_STRHEXARRAY, /* cmd */
691 [2] = SCA_HEX, /* arg */ },
692 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300693#else
694 [2] = SCA_HEX, /* arg */ }, },
695#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300696 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300697 { .name = "kill", .errmsg = true,
698 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300699 { .name = "lchown", .errmsg = true, },
700 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300701 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300702 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300703 { .name = "listxattr", .errmsg = true, },
704 { .name = "llistxattr", .errmsg = true, },
705 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300706 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300707 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300708 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300709 { .name = "lsetxattr", .errmsg = true, },
710 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
711 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300712 { .name = "madvise", .errmsg = true,
713 .arg_scnprintf = { [0] = SCA_HEX, /* start */
714 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300715 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300716 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300717 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
718 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300719 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300720 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300721 { .name = "mlock", .errmsg = true,
722 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
723 { .name = "mlockall", .errmsg = true,
724 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300725 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200726/* The standard mmap maps to old_mmap on s390x */
727#if defined(__s390x__)
728 .alias = "old_mmap",
729#endif
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300730 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300731 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300732 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300733 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300734 .arg_scnprintf = { [0] = SCA_HEX, /* start */
735 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300736 { .name = "mq_unlink", .errmsg = true,
737 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300738 { .name = "mremap", .hexret = true,
739 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300740 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300741 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300742 { .name = "munlock", .errmsg = true,
743 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300744 { .name = "munmap", .errmsg = true,
745 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300746 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300747 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300748 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300749 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300750 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300751 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300752 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300753 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
754 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300755 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300756 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
757 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300758 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300759 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300760 [3] = SCA_FD, /* group_fd */
761 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300762 { .name = "pipe2", .errmsg = true,
763 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300764 { .name = "poll", .errmsg = true, .timeout = true, },
765 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300766 { .name = "pread", .errmsg = true, .alias = "pread64", },
767 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300768 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300769 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
770 { .name = "pwritev", .errmsg = true, },
771 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300772 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300773 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300774 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300775 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300776 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300777 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300778 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300779 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300780 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300781 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300782 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300783 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300784 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300785 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300786 { .name = "rt_sigaction", .errmsg = true,
787 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300788 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300789 { .name = "rt_sigqueueinfo", .errmsg = true,
790 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
791 { .name = "rt_tgsigqueueinfo", .errmsg = true,
792 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300793 { .name = "sched_getattr", .errmsg = true, },
794 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300795 { .name = "sched_setscheduler", .errmsg = true,
796 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300797 { .name = "seccomp", .errmsg = true,
798 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
799 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300800 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300801 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300802 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300803 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300804 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300805 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300806 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300807 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300808 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300809 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300810 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300811 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300812 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300813 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300814 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
815 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300816 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300817 { .name = "socketpair", .errmsg = true,
818 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
819 [1] = SCA_SK_TYPE, /* type */ },
820 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300821 { .name = "stat", .errmsg = true, .alias = "newstat", },
822 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300823 { .name = "statx", .errmsg = true,
824 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
825 [2] = SCA_STATX_FLAGS, /* flags */
826 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300827 { .name = "swapoff", .errmsg = true,
828 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
829 { .name = "swapon", .errmsg = true,
830 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300831 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300832 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300833 { .name = "tgkill", .errmsg = true,
834 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
835 { .name = "tkill", .errmsg = true,
836 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300837 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300838 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300839 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300840 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
841 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300842 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300843 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
844 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300845 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300846 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300847 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300848 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300849 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300850 { .name = "write", .errmsg = true, },
851 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300852};
853
854static int syscall_fmt__cmp(const void *name, const void *fmtp)
855{
856 const struct syscall_fmt *fmt = fmtp;
857 return strcmp(name, fmt->name);
858}
859
860static struct syscall_fmt *syscall_fmt__find(const char *name)
861{
862 const int nmemb = ARRAY_SIZE(syscall_fmts);
863 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
864}
865
866struct syscall {
867 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300868 int nr_args;
869 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300870 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300871 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300872 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300873 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300874 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300875};
876
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300877/*
878 * We need to have this 'calculated' boolean because in some cases we really
879 * don't know what is the duration of a syscall, for instance, when we start
880 * a session and some threads are waiting for a syscall to finish, say 'poll',
881 * in which case all we can do is to print "( ? ) for duration and for the
882 * start timestamp.
883 */
884static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200885{
886 double duration = (double)t / NSEC_PER_MSEC;
887 size_t printed = fprintf(fp, "(");
888
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300889 if (!calculated)
890 printed += fprintf(fp, " ? ");
891 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200892 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
893 else if (duration >= 0.01)
894 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
895 else
896 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300897 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200898}
899
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300900/**
901 * filename.ptr: The filename char pointer that will be vfs_getname'd
902 * filename.entry_str_pos: Where to insert the string translated from
903 * filename.ptr by the vfs_getname tracepoint/kprobe.
904 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300905struct thread_trace {
906 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300907 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300908 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400909 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300910 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300911 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300912 struct {
913 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300914 short int entry_str_pos;
915 bool pending_open;
916 unsigned int namelen;
917 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300918 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300919 struct {
920 int max;
921 char **table;
922 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600923
924 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300925};
926
927static struct thread_trace *thread_trace__new(void)
928{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300929 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
930
931 if (ttrace)
932 ttrace->paths.max = -1;
933
David Ahernbf2575c2013-10-08 21:26:53 -0600934 ttrace->syscall_stats = intlist__new(NULL);
935
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300936 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300937}
938
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300939static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300940{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300941 struct thread_trace *ttrace;
942
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300943 if (thread == NULL)
944 goto fail;
945
Namhyung Kim89dceb22014-10-06 09:46:03 +0900946 if (thread__priv(thread) == NULL)
947 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300948
Namhyung Kim89dceb22014-10-06 09:46:03 +0900949 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300950 goto fail;
951
Namhyung Kim89dceb22014-10-06 09:46:03 +0900952 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300953 ++ttrace->nr_events;
954
955 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300956fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300957 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300958 "WARNING: not enough memory, dropping samples!\n");
959 return NULL;
960}
961
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400962#define TRACE_PFMAJ (1 << 0)
963#define TRACE_PFMIN (1 << 1)
964
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300965static const size_t trace__entry_str_size = 2048;
966
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300967static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300968{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900969 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300970
971 if (fd > ttrace->paths.max) {
972 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
973
974 if (npath == NULL)
975 return -1;
976
977 if (ttrace->paths.max != -1) {
978 memset(npath + ttrace->paths.max + 1, 0,
979 (fd - ttrace->paths.max) * sizeof(char *));
980 } else {
981 memset(npath, 0, (fd + 1) * sizeof(char *));
982 }
983
984 ttrace->paths.table = npath;
985 ttrace->paths.max = fd;
986 }
987
988 ttrace->paths.table[fd] = strdup(pathname);
989
990 return ttrace->paths.table[fd] != NULL ? 0 : -1;
991}
992
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300993static int thread__read_fd_path(struct thread *thread, int fd)
994{
995 char linkname[PATH_MAX], pathname[PATH_MAX];
996 struct stat st;
997 int ret;
998
999 if (thread->pid_ == thread->tid) {
1000 scnprintf(linkname, sizeof(linkname),
1001 "/proc/%d/fd/%d", thread->pid_, fd);
1002 } else {
1003 scnprintf(linkname, sizeof(linkname),
1004 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1005 }
1006
1007 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1008 return -1;
1009
1010 ret = readlink(linkname, pathname, sizeof(pathname));
1011
1012 if (ret < 0 || ret > st.st_size)
1013 return -1;
1014
1015 pathname[ret] = '\0';
1016 return trace__set_fd_pathname(thread, fd, pathname);
1017}
1018
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001019static const char *thread__fd_path(struct thread *thread, int fd,
1020 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001021{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001022 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001023
1024 if (ttrace == NULL)
1025 return NULL;
1026
1027 if (fd < 0)
1028 return NULL;
1029
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001030 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001031 if (!trace->live)
1032 return NULL;
1033 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001034 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001035 return NULL;
1036 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001037
1038 return ttrace->paths.table[fd];
1039}
1040
1041static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1042 struct syscall_arg *arg)
1043{
1044 int fd = arg->val;
1045 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001046 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001047
1048 if (path)
1049 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1050
1051 return printed;
1052}
1053
1054static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1055 struct syscall_arg *arg)
1056{
1057 int fd = arg->val;
1058 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001059 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001060
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001061 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1062 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001063
1064 return printed;
1065}
1066
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001067static void thread__set_filename_pos(struct thread *thread, const char *bf,
1068 unsigned long ptr)
1069{
1070 struct thread_trace *ttrace = thread__priv(thread);
1071
1072 ttrace->filename.ptr = ptr;
1073 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1074}
1075
1076static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1077 struct syscall_arg *arg)
1078{
1079 unsigned long ptr = arg->val;
1080
1081 if (!arg->trace->vfs_getname)
1082 return scnprintf(bf, size, "%#x", ptr);
1083
1084 thread__set_filename_pos(arg->thread, bf, ptr);
1085 return 0;
1086}
1087
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001088static bool trace__filter_duration(struct trace *trace, double t)
1089{
1090 return t < (trace->duration_filter * NSEC_PER_MSEC);
1091}
1092
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001093static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094{
1095 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1096
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001097 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098}
1099
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001100/*
1101 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1102 * using ttrace->entry_time for a thread that receives a sys_exit without
1103 * first having received a sys_enter ("poll" issued before tracing session
1104 * starts, lost sys_enter exit due to ring buffer overflow).
1105 */
1106static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1107{
1108 if (tstamp > 0)
1109 return __trace__fprintf_tstamp(trace, tstamp, fp);
1110
1111 return fprintf(fp, " ? ");
1112}
1113
Namhyung Kimf15eb532012-10-05 14:02:16 +09001114static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001115static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001116
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001117static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001118{
1119 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001120 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001121}
1122
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001123static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001124 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125{
1126 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001127 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001129 if (trace->multiple_threads) {
1130 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001131 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001132 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001133 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001134
1135 return printed;
1136}
1137
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001138static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001139 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001140{
1141 int ret = 0;
1142
1143 switch (event->header.type) {
1144 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001145 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001147 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001148 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001149 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001150 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001151 break;
1152 }
1153
1154 return ret;
1155}
1156
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001157static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001158 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001159 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001160 struct machine *machine)
1161{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001162 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001163 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001164}
1165
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001166static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1167{
1168 struct machine *machine = vmachine;
1169
1170 if (machine->kptr_restrict_warned)
1171 return NULL;
1172
1173 if (symbol_conf.kptr_restrict) {
1174 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1175 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1176 "Kernel samples will not be resolved.\n");
1177 machine->kptr_restrict_warned = true;
1178 return NULL;
1179 }
1180
1181 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1182}
1183
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001184static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1185{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001186 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001187
1188 if (err)
1189 return err;
1190
David Ahern8fb598e2013-09-28 13:13:00 -06001191 trace->host = machine__new_host();
1192 if (trace->host == NULL)
1193 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001194
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001195 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001196 return -errno;
1197
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001198 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001199 evlist->threads, trace__tool_process, false,
1200 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001201 if (err)
1202 symbol__exit();
1203
1204 return err;
1205}
1206
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001207static int syscall__set_arg_fmts(struct syscall *sc)
1208{
1209 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001210 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001211
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001212 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001213 if (sc->arg_scnprintf == NULL)
1214 return -1;
1215
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001216 if (sc->fmt)
1217 sc->arg_parm = sc->fmt->arg_parm;
1218
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001219 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001220 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1221 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001222 else if (strcmp(field->type, "const char *") == 0 &&
1223 (strcmp(field->name, "filename") == 0 ||
1224 strcmp(field->name, "path") == 0 ||
1225 strcmp(field->name, "pathname") == 0))
1226 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001227 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001228 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001229 else if (strcmp(field->type, "pid_t") == 0)
1230 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001231 else if (strcmp(field->type, "umode_t") == 0)
1232 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001233 else if ((strcmp(field->type, "int") == 0 ||
1234 strcmp(field->type, "unsigned int") == 0 ||
1235 strcmp(field->type, "long") == 0) &&
1236 (len = strlen(field->name)) >= 2 &&
1237 strcmp(field->name + len - 2, "fd") == 0) {
1238 /*
1239 * /sys/kernel/tracing/events/syscalls/sys_enter*
1240 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1241 * 65 int
1242 * 23 unsigned int
1243 * 7 unsigned long
1244 */
1245 sc->arg_scnprintf[idx] = SCA_FD;
1246 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001247 ++idx;
1248 }
1249
1250 return 0;
1251}
1252
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001253static int trace__read_syscall_info(struct trace *trace, int id)
1254{
1255 char tp_name[128];
1256 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001257 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001258
1259 if (name == NULL)
1260 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001261
1262 if (id > trace->syscalls.max) {
1263 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1264
1265 if (nsyscalls == NULL)
1266 return -1;
1267
1268 if (trace->syscalls.max != -1) {
1269 memset(nsyscalls + trace->syscalls.max + 1, 0,
1270 (id - trace->syscalls.max) * sizeof(*sc));
1271 } else {
1272 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1273 }
1274
1275 trace->syscalls.table = nsyscalls;
1276 trace->syscalls.max = id;
1277 }
1278
1279 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001280 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001281
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001282 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001283
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001284 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001285 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001286
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001287 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001288 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001289 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001290 }
1291
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001292 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001293 return -1;
1294
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001295 sc->args = sc->tp_format->format.fields;
1296 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001297 /*
1298 * We need to check and discard the first variable '__syscall_nr'
1299 * or 'nr' that mean the syscall number. It is needless here.
1300 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1301 */
1302 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001303 sc->args = sc->args->next;
1304 --sc->nr_args;
1305 }
1306
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001307 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1308
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001309 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001310}
1311
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001312static int trace__validate_ev_qualifier(struct trace *trace)
1313{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001314 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001315 struct str_node *pos;
1316
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001317 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1318 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1319 sizeof(trace->ev_qualifier_ids.entries[0]));
1320
1321 if (trace->ev_qualifier_ids.entries == NULL) {
1322 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1323 trace->output);
1324 err = -EINVAL;
1325 goto out;
1326 }
1327
1328 i = 0;
1329
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001330 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001331 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001332 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001333
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001334 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001335 if (err == 0) {
1336 fputs("Error:\tInvalid syscall ", trace->output);
1337 err = -EINVAL;
1338 } else {
1339 fputs(", ", trace->output);
1340 }
1341
1342 fputs(sc, trace->output);
1343 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001344
1345 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001346 }
1347
1348 if (err < 0) {
1349 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1350 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001351 zfree(&trace->ev_qualifier_ids.entries);
1352 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001353 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001354out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001355 return err;
1356}
1357
David Ahern55d43bca2015-02-19 15:00:22 -05001358/*
1359 * args is to be interpreted as a series of longs but we need to handle
1360 * 8-byte unaligned accesses. args points to raw_data within the event
1361 * and raw_data is guaranteed to be 8-byte unaligned because it is
1362 * preceded by raw_size which is a u32. So we need to copy args to a temp
1363 * variable to read it. Most notably this avoids extended load instructions
1364 * on unaligned addresses
1365 */
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001366static unsigned long __syscall_arg__val(unsigned char *args, u8 idx)
1367{
1368 unsigned long val;
1369 unsigned char *p = args + sizeof(unsigned long) * idx;
1370
1371 memcpy(&val, p, sizeof(val));
1372 return val;
1373}
1374
1375unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
1376{
1377 return __syscall_arg__val(arg->args, idx);
1378}
David Ahern55d43bca2015-02-19 15:00:22 -05001379
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001380static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001381 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001382 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001383{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001384 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001385 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001386
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001387 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001388 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001389 u8 bit = 1;
1390 struct syscall_arg arg = {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001391 .args = args,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001392 .idx = 0,
1393 .mask = 0,
1394 .trace = trace,
1395 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001396 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001397
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001398 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001399 field = field->next, ++arg.idx, bit <<= 1) {
1400 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001401 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001402
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001403 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001404
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001405 /*
1406 * Suppress this argument if its value is zero and
1407 * and we don't have a string associated in an
1408 * strarray for it.
1409 */
David Ahern55d43bca2015-02-19 15:00:22 -05001410 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001411 !(sc->arg_scnprintf &&
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -03001412 (sc->arg_scnprintf[arg.idx] == SCA_STRARRAY ||
1413 sc->arg_scnprintf[arg.idx] == SCA_STRARRAYS) &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001414 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001415 continue;
1416
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001417 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001418 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001419 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001420 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001421 if (sc->arg_parm)
1422 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001423 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1424 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001425 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001426 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001427 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001428 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001429 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001430 } else if (IS_ERR(sc->tp_format)) {
1431 /*
1432 * If we managed to read the tracepoint /format file, then we
1433 * may end up not having any args, like with gettid(), so only
1434 * print the raw args when we didn't manage to read it.
1435 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001436 int i = 0;
1437
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001438 while (i < 6) {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001439 val = __syscall_arg__val(args, i);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001440 printed += scnprintf(bf + printed, size - printed,
1441 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001442 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001443 ++i;
1444 }
1445 }
1446
1447 return printed;
1448}
1449
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001450typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001451 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001452 struct perf_sample *sample);
1453
1454static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001455 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001456{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001457
1458 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001459
1460 /*
1461 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1462 * before that, leaving at a higher verbosity level till that is
1463 * explained. Reproduced with plain ftrace with:
1464 *
1465 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1466 * grep "NR -1 " /t/trace_pipe
1467 *
1468 * After generating some load on the machine.
1469 */
1470 if (verbose > 1) {
1471 static u64 n;
1472 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1473 id, perf_evsel__name(evsel), ++n);
1474 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001475 return NULL;
1476 }
1477
1478 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1479 trace__read_syscall_info(trace, id))
1480 goto out_cant_read;
1481
1482 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1483 goto out_cant_read;
1484
1485 return &trace->syscalls.table[id];
1486
1487out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001488 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001489 fprintf(trace->output, "Problems reading syscall %d", id);
1490 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1491 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1492 fputs(" information\n", trace->output);
1493 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001494 return NULL;
1495}
1496
David Ahernbf2575c2013-10-08 21:26:53 -06001497static void thread__update_stats(struct thread_trace *ttrace,
1498 int id, struct perf_sample *sample)
1499{
1500 struct int_node *inode;
1501 struct stats *stats;
1502 u64 duration = 0;
1503
1504 inode = intlist__findnew(ttrace->syscall_stats, id);
1505 if (inode == NULL)
1506 return;
1507
1508 stats = inode->priv;
1509 if (stats == NULL) {
1510 stats = malloc(sizeof(struct stats));
1511 if (stats == NULL)
1512 return;
1513 init_stats(stats);
1514 inode->priv = stats;
1515 }
1516
1517 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1518 duration = sample->time - ttrace->entry_time;
1519
1520 update_stats(stats, duration);
1521}
1522
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001523static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1524{
1525 struct thread_trace *ttrace;
1526 u64 duration;
1527 size_t printed;
1528
1529 if (trace->current == NULL)
1530 return 0;
1531
1532 ttrace = thread__priv(trace->current);
1533
1534 if (!ttrace->entry_pending)
1535 return 0;
1536
1537 duration = sample->time - ttrace->entry_time;
1538
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001539 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001540 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1541 ttrace->entry_pending = false;
1542
1543 return printed;
1544}
1545
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001546static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001547 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001548 struct perf_sample *sample)
1549{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001550 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001551 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001552 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001553 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001554 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001555 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001556 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001557
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001558 if (sc == NULL)
1559 return -1;
1560
David Ahern8fb598e2013-09-28 13:13:00 -06001561 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001562 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001563 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001564 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001565
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001566 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001567
1568 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001569 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001570 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001571 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001572 }
1573
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001574 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001575 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001576
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001577 ttrace->entry_time = sample->time;
1578 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001579 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001580
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001581 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001582 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001583
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001584 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001585 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001586 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001587 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001588 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001589 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001590 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001591 /* See trace__vfs_getname & trace__sys_exit */
1592 ttrace->filename.pending_open = false;
1593 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001594
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001595 if (trace->current != thread) {
1596 thread__put(trace->current);
1597 trace->current = thread__get(thread);
1598 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001599 err = 0;
1600out_put:
1601 thread__put(thread);
1602 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001603}
1604
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001605static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1606 struct perf_sample *sample,
1607 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001608{
1609 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001610
1611 if (machine__resolve(trace->host, &al, sample) < 0 ||
1612 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1613 return -1;
1614
1615 return 0;
1616}
1617
1618static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1619{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001620 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001621 const unsigned int print_opts = EVSEL__PRINT_SYM |
1622 EVSEL__PRINT_DSO |
1623 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001624
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001625 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001626}
1627
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001628static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001629 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001630 struct perf_sample *sample)
1631{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001632 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001633 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001634 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001635 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001636 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001637 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001638 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001639
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001640 if (sc == NULL)
1641 return -1;
1642
David Ahern8fb598e2013-09-28 13:13:00 -06001643 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001644 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001645 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001646 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001647
David Ahernbf2575c2013-10-08 21:26:53 -06001648 if (trace->summary)
1649 thread__update_stats(ttrace, id, sample);
1650
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001651 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001652
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001653 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001654 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1655 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001656 ++trace->stats.vfs_getname;
1657 }
1658
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001659 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001660 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001661 if (trace__filter_duration(trace, duration))
1662 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001663 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001664 } else if (trace->duration_filter)
1665 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001666
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001667 if (sample->callchain) {
1668 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1669 if (callchain_ret == 0) {
1670 if (callchain_cursor.nr < trace->min_stack)
1671 goto out;
1672 callchain_ret = 1;
1673 }
1674 }
1675
David Ahernfd2eaba2013-11-12 09:31:15 -07001676 if (trace->summary_only)
1677 goto out;
1678
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001679 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680
1681 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001682 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001683 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001684 fprintf(trace->output, " ... [");
1685 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1686 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001687 }
1688
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001689 if (sc->fmt == NULL) {
1690signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001691 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001692 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001693 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001694 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001695 *e = audit_errno_to_name(-ret);
1696
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001697 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001698 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001699 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001700 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001701 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001702 else if (sc->fmt->errpid) {
1703 struct thread *child = machine__find_thread(trace->host, ret, ret);
1704
1705 if (child != NULL) {
1706 fprintf(trace->output, ") = %ld", ret);
1707 if (child->comm_set)
1708 fprintf(trace->output, " (%s)", thread__comm_str(child));
1709 thread__put(child);
1710 }
1711 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001712 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001713
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001714 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001715
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001716 if (callchain_ret > 0)
1717 trace__fprintf_callchain(trace, sample);
1718 else if (callchain_ret < 0)
1719 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001720out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001721 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001722 err = 0;
1723out_put:
1724 thread__put(thread);
1725 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001726}
1727
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001728static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001729 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001730 struct perf_sample *sample)
1731{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001732 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1733 struct thread_trace *ttrace;
1734 size_t filename_len, entry_str_len, to_move;
1735 ssize_t remaining_space;
1736 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001737 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001738
1739 if (!thread)
1740 goto out;
1741
1742 ttrace = thread__priv(thread);
1743 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001744 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001745
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001746 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001747 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001748 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001749
1750 if (ttrace->filename.namelen < filename_len) {
1751 char *f = realloc(ttrace->filename.name, filename_len + 1);
1752
1753 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001754 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001755
1756 ttrace->filename.namelen = filename_len;
1757 ttrace->filename.name = f;
1758 }
1759
1760 strcpy(ttrace->filename.name, filename);
1761 ttrace->filename.pending_open = true;
1762
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001763 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001764 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001765
1766 entry_str_len = strlen(ttrace->entry_str);
1767 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1768 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001769 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001770
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001771 if (filename_len > (size_t)remaining_space) {
1772 filename += filename_len - remaining_space;
1773 filename_len = remaining_space;
1774 }
1775
1776 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1777 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1778 memmove(pos + filename_len, pos, to_move);
1779 memcpy(pos, filename, filename_len);
1780
1781 ttrace->filename.ptr = 0;
1782 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001783out_put:
1784 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001785out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001786 return 0;
1787}
1788
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001789static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001790 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001791 struct perf_sample *sample)
1792{
1793 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1794 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001795 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001796 sample->pid,
1797 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001798 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001799
1800 if (ttrace == NULL)
1801 goto out_dump;
1802
1803 ttrace->runtime_ms += runtime_ms;
1804 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001805out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001806 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001807 return 0;
1808
1809out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001810 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001811 evsel->name,
1812 perf_evsel__strval(evsel, sample, "comm"),
1813 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1814 runtime,
1815 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001816 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001817}
1818
Wang Nan1d6c9402016-02-26 09:31:55 +00001819static void bpf_output__printer(enum binary_printer_ops op,
1820 unsigned int val, void *extra)
1821{
1822 FILE *output = extra;
1823 unsigned char ch = (unsigned char)val;
1824
1825 switch (op) {
1826 case BINARY_PRINT_CHAR_DATA:
1827 fprintf(output, "%c", isprint(ch) ? ch : '.');
1828 break;
1829 case BINARY_PRINT_DATA_BEGIN:
1830 case BINARY_PRINT_LINE_BEGIN:
1831 case BINARY_PRINT_ADDR:
1832 case BINARY_PRINT_NUM_DATA:
1833 case BINARY_PRINT_NUM_PAD:
1834 case BINARY_PRINT_SEP:
1835 case BINARY_PRINT_CHAR_PAD:
1836 case BINARY_PRINT_LINE_END:
1837 case BINARY_PRINT_DATA_END:
1838 default:
1839 break;
1840 }
1841}
1842
1843static void bpf_output__fprintf(struct trace *trace,
1844 struct perf_sample *sample)
1845{
1846 print_binary(sample->raw_data, sample->raw_size, 8,
1847 bpf_output__printer, trace->output);
1848}
1849
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001850static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1851 union perf_event *event __maybe_unused,
1852 struct perf_sample *sample)
1853{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001854 int callchain_ret = 0;
1855
1856 if (sample->callchain) {
1857 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1858 if (callchain_ret == 0) {
1859 if (callchain_cursor.nr < trace->min_stack)
1860 goto out;
1861 callchain_ret = 1;
1862 }
1863 }
1864
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001865 trace__printf_interrupted_entry(trace, sample);
1866 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001867
1868 if (trace->trace_syscalls)
1869 fprintf(trace->output, "( ): ");
1870
1871 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001872
Wang Nan1d6c9402016-02-26 09:31:55 +00001873 if (perf_evsel__is_bpf_output(evsel)) {
1874 bpf_output__fprintf(trace, sample);
1875 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001876 event_format__fprintf(evsel->tp_format, sample->cpu,
1877 sample->raw_data, sample->raw_size,
1878 trace->output);
1879 }
1880
1881 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001882
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001883 if (callchain_ret > 0)
1884 trace__fprintf_callchain(trace, sample);
1885 else if (callchain_ret < 0)
1886 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1887out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001888 return 0;
1889}
1890
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001891static void print_location(FILE *f, struct perf_sample *sample,
1892 struct addr_location *al,
1893 bool print_dso, bool print_sym)
1894{
1895
Namhyung Kimbb963e12017-02-17 17:17:38 +09001896 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001897 fprintf(f, "%s@", al->map->dso->long_name);
1898
Namhyung Kimbb963e12017-02-17 17:17:38 +09001899 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001900 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001901 al->addr - al->sym->start);
1902 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001903 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001904 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001905 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001906}
1907
1908static int trace__pgfault(struct trace *trace,
1909 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001910 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001911 struct perf_sample *sample)
1912{
1913 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001914 struct addr_location al;
1915 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001916 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001917 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001918 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001919
1920 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001921
1922 if (sample->callchain) {
1923 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1924 if (callchain_ret == 0) {
1925 if (callchain_cursor.nr < trace->min_stack)
1926 goto out_put;
1927 callchain_ret = 1;
1928 }
1929 }
1930
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001931 ttrace = thread__trace(thread, trace->output);
1932 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001933 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001934
1935 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1936 ttrace->pfmaj++;
1937 else
1938 ttrace->pfmin++;
1939
1940 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001941 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001942
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001943 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001944 sample->ip, &al);
1945
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001946 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001947
1948 fprintf(trace->output, "%sfault [",
1949 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1950 "maj" : "min");
1951
1952 print_location(trace->output, sample, &al, false, true);
1953
1954 fprintf(trace->output, "] => ");
1955
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001956 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001957 sample->addr, &al);
1958
1959 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001960 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001961 MAP__FUNCTION, sample->addr, &al);
1962
1963 if (al.map)
1964 map_type = 'x';
1965 else
1966 map_type = '?';
1967 }
1968
1969 print_location(trace->output, sample, &al, true, false);
1970
1971 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001972
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001973 if (callchain_ret > 0)
1974 trace__fprintf_callchain(trace, sample);
1975 else if (callchain_ret < 0)
1976 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001977out:
1978 err = 0;
1979out_put:
1980 thread__put(thread);
1981 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001982}
1983
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001984static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001985 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001986 struct perf_sample *sample)
1987{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001988 /*
1989 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1990 * and don't use sample->time unconditionally, we may end up having
1991 * some other event in the future without PERF_SAMPLE_TIME for good
1992 * reason, i.e. we may not be interested in its timestamps, just in
1993 * it taking place, picking some piece of information when it
1994 * appears in our event stream (vfs_getname comes to mind).
1995 */
1996 if (trace->base_time == 0 && !trace->full_time &&
1997 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001998 trace->base_time = sample->time;
1999}
2000
David Ahern6810fc92013-08-28 22:29:52 -06002001static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002002 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002003 struct perf_sample *sample,
2004 struct perf_evsel *evsel,
2005 struct machine *machine __maybe_unused)
2006{
2007 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002008 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002009 int err = 0;
2010
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002011 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002012
David Ahernaa07df62016-11-25 09:29:52 -07002013 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2014 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002015 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002016
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002017 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002018
David Ahern31605652013-12-04 19:41:41 -07002019 if (handler) {
2020 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002021 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002022 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002023out:
2024 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002025 return err;
2026}
2027
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002028static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002029{
2030 unsigned int rec_argc, i, j;
2031 const char **rec_argv;
2032 const char * const record_args[] = {
2033 "record",
2034 "-R",
2035 "-m", "1024",
2036 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002037 };
2038
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002039 const char * const sc_args[] = { "-e", };
2040 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2041 const char * const majpf_args[] = { "-e", "major-faults" };
2042 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2043 const char * const minpf_args[] = { "-e", "minor-faults" };
2044 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2045
David Ahern9aca7f12013-12-04 19:41:39 -07002046 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002047 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2048 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002049 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2050
2051 if (rec_argv == NULL)
2052 return -ENOMEM;
2053
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002054 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002055 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002056 rec_argv[j++] = record_args[i];
2057
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002058 if (trace->trace_syscalls) {
2059 for (i = 0; i < sc_args_nr; i++)
2060 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002061
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002062 /* event string may be different for older kernels - e.g., RHEL6 */
2063 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2064 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2065 else if (is_valid_tracepoint("syscalls:sys_enter"))
2066 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2067 else {
2068 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2069 return -1;
2070 }
David Ahern9aca7f12013-12-04 19:41:39 -07002071 }
David Ahern9aca7f12013-12-04 19:41:39 -07002072
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002073 if (trace->trace_pgfaults & TRACE_PFMAJ)
2074 for (i = 0; i < majpf_args_nr; i++)
2075 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002076
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002077 if (trace->trace_pgfaults & TRACE_PFMIN)
2078 for (i = 0; i < minpf_args_nr; i++)
2079 rec_argv[j++] = minpf_args[i];
2080
2081 for (i = 0; i < (unsigned int)argc; i++)
2082 rec_argv[j++] = argv[i];
2083
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002084 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002085}
2086
David Ahernbf2575c2013-10-08 21:26:53 -06002087static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2088
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002089static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002090{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002091 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002092
2093 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002094 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002095
2096 if (perf_evsel__field(evsel, "pathname") == NULL) {
2097 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002098 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002099 }
2100
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002101 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002102 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002103 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002104}
2105
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002106static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002107{
2108 struct perf_evsel *evsel;
2109 struct perf_event_attr attr = {
2110 .type = PERF_TYPE_SOFTWARE,
2111 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002112 };
2113
2114 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002115 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002116
2117 event_attr_init(&attr);
2118
2119 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002120 if (evsel)
2121 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002122
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002123 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002124}
2125
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002126static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2127{
2128 const u32 type = event->header.type;
2129 struct perf_evsel *evsel;
2130
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002131 if (type != PERF_RECORD_SAMPLE) {
2132 trace__process_event(trace, trace->host, event, sample);
2133 return;
2134 }
2135
2136 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2137 if (evsel == NULL) {
2138 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2139 return;
2140 }
2141
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002142 trace__set_base_time(trace, evsel, sample);
2143
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002144 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2145 sample->raw_data == NULL) {
2146 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2147 perf_evsel__name(evsel), sample->tid,
2148 sample->cpu, sample->raw_size);
2149 } else {
2150 tracepoint_handler handler = evsel->handler;
2151 handler(trace, evsel, event, sample);
2152 }
2153}
2154
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002155static int trace__add_syscall_newtp(struct trace *trace)
2156{
2157 int ret = -1;
2158 struct perf_evlist *evlist = trace->evlist;
2159 struct perf_evsel *sys_enter, *sys_exit;
2160
2161 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2162 if (sys_enter == NULL)
2163 goto out;
2164
2165 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2166 goto out_delete_sys_enter;
2167
2168 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2169 if (sys_exit == NULL)
2170 goto out_delete_sys_enter;
2171
2172 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2173 goto out_delete_sys_exit;
2174
2175 perf_evlist__add(evlist, sys_enter);
2176 perf_evlist__add(evlist, sys_exit);
2177
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002178 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002179 /*
2180 * We're interested only in the user space callchain
2181 * leading to the syscall, allow overriding that for
2182 * debugging reasons using --kernel_syscall_callchains
2183 */
2184 sys_exit->attr.exclude_callchain_kernel = 1;
2185 }
2186
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002187 trace->syscalls.events.sys_enter = sys_enter;
2188 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002189
2190 ret = 0;
2191out:
2192 return ret;
2193
2194out_delete_sys_exit:
2195 perf_evsel__delete_priv(sys_exit);
2196out_delete_sys_enter:
2197 perf_evsel__delete_priv(sys_enter);
2198 goto out;
2199}
2200
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002201static int trace__set_ev_qualifier_filter(struct trace *trace)
2202{
2203 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002204 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002205 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2206 trace->ev_qualifier_ids.nr,
2207 trace->ev_qualifier_ids.entries);
2208
2209 if (filter == NULL)
2210 goto out_enomem;
2211
Mathieu Poirier3541c032016-09-16 08:44:04 -06002212 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2213 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002214 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002215 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002216 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002217
2218 free(filter);
2219out:
2220 return err;
2221out_enomem:
2222 errno = ENOMEM;
2223 goto out;
2224}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002225
Namhyung Kimf15eb532012-10-05 14:02:16 +09002226static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002227{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002228 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002229 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002230 int err = -1, i;
2231 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002232 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002233 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002234
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002235 trace->live = true;
2236
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002237 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002238 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002239
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002240 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002241 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002242
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002243 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2244 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2245 if (pgfault_maj == NULL)
2246 goto out_error_mem;
2247 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002248 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002249
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002250 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2251 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2252 if (pgfault_min == NULL)
2253 goto out_error_mem;
2254 perf_evlist__add(evlist, pgfault_min);
2255 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002256
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002257 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002258 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2259 trace__sched_stat_runtime))
2260 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002261
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002262 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2263 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002264 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002265 goto out_delete_evlist;
2266 }
2267
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002268 err = trace__symbols_init(trace, evlist);
2269 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002270 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002271 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002272 }
2273
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002274 perf_evlist__config(evlist, &trace->opts, NULL);
2275
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002276 if (callchain_param.enabled) {
2277 bool use_identifier = false;
2278
2279 if (trace->syscalls.events.sys_exit) {
2280 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2281 &trace->opts, &callchain_param);
2282 use_identifier = true;
2283 }
2284
2285 if (pgfault_maj) {
2286 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2287 use_identifier = true;
2288 }
2289
2290 if (pgfault_min) {
2291 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2292 use_identifier = true;
2293 }
2294
2295 if (use_identifier) {
2296 /*
2297 * Now we have evsels with different sample_ids, use
2298 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2299 * from a fixed position in each ring buffer record.
2300 *
2301 * As of this the changeset introducing this comment, this
2302 * isn't strictly needed, as the fields that can come before
2303 * PERF_SAMPLE_ID are all used, but we'll probably disable
2304 * some of those for things like copying the payload of
2305 * pointer syscall arguments, and for vfs_getname we don't
2306 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2307 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2308 */
2309 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2310 perf_evlist__reset_sample_bit(evlist, ID);
2311 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002312 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002313
Namhyung Kimf15eb532012-10-05 14:02:16 +09002314 signal(SIGCHLD, sig_handler);
2315 signal(SIGINT, sig_handler);
2316
2317 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002318 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002319 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002320 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002321 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002322 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002323 }
2324 }
2325
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002326 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002327 if (err < 0)
2328 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002329
Wang Nanba504232016-02-26 09:31:54 +00002330 err = bpf__apply_obj_config();
2331 if (err) {
2332 char errbuf[BUFSIZ];
2333
2334 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2335 pr_err("ERROR: Apply config to BPF failed: %s\n",
2336 errbuf);
2337 goto out_error_open;
2338 }
2339
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002340 /*
2341 * Better not use !target__has_task() here because we need to cover the
2342 * case where no threads were specified in the command line, but a
2343 * workload was, and in that case we will fill in the thread_map when
2344 * we fork the workload in perf_evlist__prepare_workload.
2345 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002346 if (trace->filter_pids.nr > 0)
2347 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002348 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002349 err = perf_evlist__set_filter_pid(evlist, getpid());
2350
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002351 if (err < 0)
2352 goto out_error_mem;
2353
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002354 if (trace->ev_qualifier_ids.nr > 0) {
2355 err = trace__set_ev_qualifier_filter(trace);
2356 if (err < 0)
2357 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002358
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002359 pr_debug("event qualifier tracepoint filter: %s\n",
2360 trace->syscalls.events.sys_exit->filter);
2361 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002362
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002363 err = perf_evlist__apply_filters(evlist, &evsel);
2364 if (err < 0)
2365 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002366
Jiri Olsaf8850372013-11-28 17:57:22 +01002367 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002368 if (err < 0)
2369 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002370
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002371 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002372 perf_evlist__enable(evlist);
2373
Namhyung Kimf15eb532012-10-05 14:02:16 +09002374 if (forks)
2375 perf_evlist__start_workload(evlist);
2376
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002377 if (trace->opts.initial_delay) {
2378 usleep(trace->opts.initial_delay * 1000);
2379 perf_evlist__enable(evlist);
2380 }
2381
Jiri Olsae13798c2015-06-23 00:36:02 +02002382 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002383 evlist->threads->nr > 1 ||
2384 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002385again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002386 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002387
2388 for (i = 0; i < evlist->nr_mmaps; i++) {
2389 union perf_event *event;
2390
2391 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002393
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002394 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002395
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002396 err = perf_evlist__parse_sample(evlist, event, &sample);
2397 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002398 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002399 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002400 }
2401
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002402 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002403next_event:
2404 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002405
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002406 if (interrupted)
2407 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002408
2409 if (done && !draining) {
2410 perf_evlist__disable(evlist);
2411 draining = true;
2412 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002413 }
2414 }
2415
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002416 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002417 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002418
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002419 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2420 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2421 draining = true;
2422
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002423 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002424 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002425 } else {
2426 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002427 }
2428
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002429out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002430 thread__zput(trace->current);
2431
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002432 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002433
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002434 if (!err) {
2435 if (trace->summary)
2436 trace__fprintf_thread_summary(trace, trace->output);
2437
2438 if (trace->show_tool_stats) {
2439 fprintf(trace->output, "Stats:\n "
2440 " vfs_getname : %" PRIu64 "\n"
2441 " proc_getname: %" PRIu64 "\n",
2442 trace->stats.vfs_getname,
2443 trace->stats.proc_getname);
2444 }
2445 }
David Ahernbf2575c2013-10-08 21:26:53 -06002446
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002447out_delete_evlist:
2448 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002449 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002450 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002451 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002452{
2453 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002454
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002455out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002456 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002457 goto out_error;
2458
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002459out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002460 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002461 goto out_error;
2462
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002463out_error_mmap:
2464 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2465 goto out_error;
2466
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002467out_error_open:
2468 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2469
2470out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002471 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302472 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002473
2474out_error_apply_filters:
2475 fprintf(trace->output,
2476 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2477 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002478 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002479 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002480}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002481out_error_mem:
2482 fprintf(trace->output, "Not enough memory to run!\n");
2483 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002484
2485out_errno:
2486 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2487 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002488}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002489
David Ahern6810fc92013-08-28 22:29:52 -06002490static int trace__replay(struct trace *trace)
2491{
2492 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002493 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002494 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002495 struct perf_data_file file = {
2496 .path = input_name,
2497 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002498 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002499 };
David Ahern6810fc92013-08-28 22:29:52 -06002500 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002501 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002502 int err = -1;
2503
2504 trace->tool.sample = trace__process_sample;
2505 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002506 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002507 trace->tool.comm = perf_event__process_comm;
2508 trace->tool.exit = perf_event__process_exit;
2509 trace->tool.fork = perf_event__process_fork;
2510 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302511 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002512 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302513 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002514
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002515 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002516 trace->tool.ordering_requires_timestamps = true;
2517
2518 /* add tid to output */
2519 trace->multiple_threads = true;
2520
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002521 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002522 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002523 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002524
David Ahernaa07df62016-11-25 09:29:52 -07002525 if (trace->opts.target.pid)
2526 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2527
2528 if (trace->opts.target.tid)
2529 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2530
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002531 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002532 goto out;
2533
David Ahern8fb598e2013-09-28 13:13:00 -06002534 trace->host = &session->machines.host;
2535
David Ahern6810fc92013-08-28 22:29:52 -06002536 err = perf_session__set_tracepoints_handlers(session, handlers);
2537 if (err)
2538 goto out;
2539
Namhyung Kim003824e2013-11-12 15:25:00 +09002540 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2541 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002542 /* older kernels have syscalls tp versus raw_syscalls */
2543 if (evsel == NULL)
2544 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2545 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002546
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002547 if (evsel &&
2548 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2549 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002550 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2551 goto out;
2552 }
2553
2554 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2555 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002556 if (evsel == NULL)
2557 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2558 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002559 if (evsel &&
2560 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2561 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002562 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002563 goto out;
2564 }
2565
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002566 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002567 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2568 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2569 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2570 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2571 evsel->handler = trace__pgfault;
2572 }
2573
David Ahern6810fc92013-08-28 22:29:52 -06002574 setup_pager();
2575
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002576 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002577 if (err)
2578 pr_err("Failed to process events, error %d", err);
2579
David Ahernbf2575c2013-10-08 21:26:53 -06002580 else if (trace->summary)
2581 trace__fprintf_thread_summary(trace, trace->output);
2582
David Ahern6810fc92013-08-28 22:29:52 -06002583out:
2584 perf_session__delete(session);
2585
2586 return err;
2587}
2588
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002589static size_t trace__fprintf_threads_header(FILE *fp)
2590{
2591 size_t printed;
2592
Pekka Enberg99ff7152013-11-12 16:42:14 +02002593 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002594
2595 return printed;
2596}
2597
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002598DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2599 struct stats *stats;
2600 double msecs;
2601 int syscall;
2602)
2603{
2604 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2605 struct stats *stats = source->priv;
2606
2607 entry->syscall = source->i;
2608 entry->stats = stats;
2609 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2610}
2611
David Ahernbf2575c2013-10-08 21:26:53 -06002612static size_t thread__dump_stats(struct thread_trace *ttrace,
2613 struct trace *trace, FILE *fp)
2614{
David Ahernbf2575c2013-10-08 21:26:53 -06002615 size_t printed = 0;
2616 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002617 struct rb_node *nd;
2618 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002619
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002620 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002621 return 0;
2622
2623 printed += fprintf(fp, "\n");
2624
Milian Wolff834fd462015-08-06 11:24:29 +02002625 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2626 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2627 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002628
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002629 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002630 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002631 if (stats) {
2632 double min = (double)(stats->min) / NSEC_PER_MSEC;
2633 double max = (double)(stats->max) / NSEC_PER_MSEC;
2634 double avg = avg_stats(stats);
2635 double pct;
2636 u64 n = (u64) stats->n;
2637
2638 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2639 avg /= NSEC_PER_MSEC;
2640
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002641 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002642 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002643 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002644 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002645 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002646 }
David Ahernbf2575c2013-10-08 21:26:53 -06002647 }
2648
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002649 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002650 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002651
2652 return printed;
2653}
2654
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002655static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002656{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002657 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002658 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002659 double ratio;
2660
2661 if (ttrace == NULL)
2662 return 0;
2663
2664 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2665
Pekka Enberg15e65c62013-11-14 18:43:30 +02002666 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002667 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002668 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002669 if (ttrace->pfmaj)
2670 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2671 if (ttrace->pfmin)
2672 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002673 if (trace->sched)
2674 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2675 else if (fputc('\n', fp) != EOF)
2676 ++printed;
2677
David Ahernbf2575c2013-10-08 21:26:53 -06002678 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002679
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002680 return printed;
2681}
David Ahern896cbb52013-09-28 13:12:59 -06002682
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002683static unsigned long thread__nr_events(struct thread_trace *ttrace)
2684{
2685 return ttrace ? ttrace->nr_events : 0;
2686}
2687
2688DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2689 struct thread *thread;
2690)
2691{
2692 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002693}
2694
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002695static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2696{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002697 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2698 size_t printed = trace__fprintf_threads_header(fp);
2699 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002700
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002701 if (threads == NULL) {
2702 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2703 return 0;
2704 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002705
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002706 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002707 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2708
2709 resort_rb__delete(threads);
2710
2711 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002712}
2713
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002714static int trace__set_duration(const struct option *opt, const char *str,
2715 int unset __maybe_unused)
2716{
2717 struct trace *trace = opt->value;
2718
2719 trace->duration_filter = atof(str);
2720 return 0;
2721}
2722
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002723static int trace__set_filter_pids(const struct option *opt, const char *str,
2724 int unset __maybe_unused)
2725{
2726 int ret = -1;
2727 size_t i;
2728 struct trace *trace = opt->value;
2729 /*
2730 * FIXME: introduce a intarray class, plain parse csv and create a
2731 * { int nr, int entries[] } struct...
2732 */
2733 struct intlist *list = intlist__new(str);
2734
2735 if (list == NULL)
2736 return -1;
2737
2738 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2739 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2740
2741 if (trace->filter_pids.entries == NULL)
2742 goto out;
2743
2744 trace->filter_pids.entries[0] = getpid();
2745
2746 for (i = 1; i < trace->filter_pids.nr; ++i)
2747 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2748
2749 intlist__delete(list);
2750 ret = 0;
2751out:
2752 return ret;
2753}
2754
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002755static int trace__open_output(struct trace *trace, const char *filename)
2756{
2757 struct stat st;
2758
2759 if (!stat(filename, &st) && st.st_size) {
2760 char oldname[PATH_MAX];
2761
2762 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2763 unlink(oldname);
2764 rename(filename, oldname);
2765 }
2766
2767 trace->output = fopen(filename, "w");
2768
2769 return trace->output == NULL ? -errno : 0;
2770}
2771
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002772static int parse_pagefaults(const struct option *opt, const char *str,
2773 int unset __maybe_unused)
2774{
2775 int *trace_pgfaults = opt->value;
2776
2777 if (strcmp(str, "all") == 0)
2778 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2779 else if (strcmp(str, "maj") == 0)
2780 *trace_pgfaults |= TRACE_PFMAJ;
2781 else if (strcmp(str, "min") == 0)
2782 *trace_pgfaults |= TRACE_PFMIN;
2783 else
2784 return -1;
2785
2786 return 0;
2787}
2788
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002789static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2790{
2791 struct perf_evsel *evsel;
2792
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002793 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002794 evsel->handler = handler;
2795}
2796
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002797/*
2798 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2799 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2800 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2801 *
2802 * It'd be better to introduce a parse_options() variant that would return a
2803 * list with the terms it didn't match to an event...
2804 */
2805static int trace__parse_events_option(const struct option *opt, const char *str,
2806 int unset __maybe_unused)
2807{
2808 struct trace *trace = (struct trace *)opt->value;
2809 const char *s = str;
2810 char *sep = NULL, *lists[2] = { NULL, NULL, };
2811 int len = strlen(str), err = -1, list;
2812 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2813 char group_name[PATH_MAX];
2814
2815 if (strace_groups_dir == NULL)
2816 return -1;
2817
2818 if (*s == '!') {
2819 ++s;
2820 trace->not_ev_qualifier = true;
2821 }
2822
2823 while (1) {
2824 if ((sep = strchr(s, ',')) != NULL)
2825 *sep = '\0';
2826
2827 list = 0;
2828 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2829 list = 1;
2830 } else {
2831 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2832 if (access(group_name, R_OK) == 0)
2833 list = 1;
2834 }
2835
2836 if (lists[list]) {
2837 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2838 } else {
2839 lists[list] = malloc(len);
2840 if (lists[list] == NULL)
2841 goto out;
2842 strcpy(lists[list], s);
2843 }
2844
2845 if (!sep)
2846 break;
2847
2848 *sep = ',';
2849 s = sep + 1;
2850 }
2851
2852 if (lists[1] != NULL) {
2853 struct strlist_config slist_config = {
2854 .dirname = strace_groups_dir,
2855 };
2856
2857 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2858 if (trace->ev_qualifier == NULL) {
2859 fputs("Not enough memory to parse event qualifier", trace->output);
2860 goto out;
2861 }
2862
2863 if (trace__validate_ev_qualifier(trace))
2864 goto out;
2865 }
2866
2867 err = 0;
2868
2869 if (lists[0]) {
2870 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2871 "event selector. use 'perf list' to list available events",
2872 parse_events_option);
2873 err = parse_events_option(&o, lists[0], 0);
2874 }
2875out:
2876 if (sep)
2877 *sep = ',';
2878
2879 return err;
2880}
2881
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002882int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002883{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002884 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002885 "perf trace [<options>] [<command>]",
2886 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002887 "perf trace record [<options>] [<command>]",
2888 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002889 NULL
2890 };
2891 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002892 .syscalls = {
2893 . max = -1,
2894 },
2895 .opts = {
2896 .target = {
2897 .uid = UINT_MAX,
2898 .uses_mmap = true,
2899 },
2900 .user_freq = UINT_MAX,
2901 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002902 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002903 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002904 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002905 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002906 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002907 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002908 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002909 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002910 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002911 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002912 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002913 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002914 OPT_CALLBACK('e', "event", &trace, "event",
2915 "event/syscall selector. use 'perf list' to list available events",
2916 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002917 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2918 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002919 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002920 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2921 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002922 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002923 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002924 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2925 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002926 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002927 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002928 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2929 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002930 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002931 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002932 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002933 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002934 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002935 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002936 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2937 "number of mmap data pages",
2938 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002939 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002940 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002941 OPT_CALLBACK(0, "duration", &trace, "float",
2942 "show only events with duration > N.M ms",
2943 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002944 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002945 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002946 OPT_BOOLEAN('T', "time", &trace.full_time,
2947 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002948 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2949 "Show only syscall summary with statistics"),
2950 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2951 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002952 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2953 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002954 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002955 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002956 OPT_CALLBACK(0, "call-graph", &trace.opts,
2957 "record_mode[,record_size]", record_callchain_help,
2958 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002959 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2960 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002961 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2962 "Set the minimum stack depth when parsing the callchain, "
2963 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002964 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2965 "Set the maximum stack depth when parsing the callchain, "
2966 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002967 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002968 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2969 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002970 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2971 "ms to wait before starting measurement after program "
2972 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002973 OPT_END()
2974 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002975 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002976 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002977 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002978 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002979 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002980
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002981 signal(SIGSEGV, sighandler_dump_stack);
2982 signal(SIGFPE, sighandler_dump_stack);
2983
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002984 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002985 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002986
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002987 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002988 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002989 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002990 goto out;
2991 }
2992
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002993 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2994 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002995
Wang Nand7888572016-04-08 15:07:24 +00002996 err = bpf__setup_stdout(trace.evlist);
2997 if (err) {
2998 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2999 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3000 goto out;
3001 }
3002
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003003 err = -1;
3004
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003005 if (trace.trace_pgfaults) {
3006 trace.opts.sample_address = true;
3007 trace.opts.sample_time = true;
3008 }
3009
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003010 if (trace.opts.mmap_pages == UINT_MAX)
3011 mmap_pages_user_set = false;
3012
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003013 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003014 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003015 max_stack_user_set = false;
3016 }
3017
3018#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003019 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003020 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3021#endif
3022
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003023 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003024 if (!mmap_pages_user_set && geteuid() == 0)
3025 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3026
Milian Wolff566a0882016-04-08 13:34:15 +02003027 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003028 }
Milian Wolff566a0882016-04-08 13:34:15 +02003029
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003030 if (trace.evlist->nr_entries > 0)
3031 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3032
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003033 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3034 return trace__record(&trace, argc-1, &argv[1]);
3035
3036 /* summary_only implies summary option, but don't overwrite summary if set */
3037 if (trace.summary_only)
3038 trace.summary = trace.summary_only;
3039
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003040 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3041 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003042 pr_err("Please specify something to trace.\n");
3043 return -1;
3044 }
3045
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003046 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003047 pr_err("The -e option can't be used with --no-syscalls.\n");
3048 goto out;
3049 }
3050
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003051 if (output_name != NULL) {
3052 err = trace__open_output(&trace, output_name);
3053 if (err < 0) {
3054 perror("failed to create output file");
3055 goto out;
3056 }
3057 }
3058
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003059 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3060
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003061 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003062 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003063 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003064 fprintf(trace.output, "%s", bf);
3065 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003066 }
3067
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003068 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003069 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003070 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003071 fprintf(trace.output, "%s", bf);
3072 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003073 }
3074
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003075 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003076 trace.opts.target.system_wide = true;
3077
David Ahern6810fc92013-08-28 22:29:52 -06003078 if (input_name)
3079 err = trace__replay(&trace);
3080 else
3081 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003082
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003083out_close:
3084 if (output_name != NULL)
3085 fclose(trace.output);
3086out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003087 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003088}