blob: ef1b1d4ea00783b4fdd60362f1edaa4149cfc5d2 [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 Melo6e7eeb52013-09-02 10:39:21 -0300395static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300396 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300397{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300398 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300399}
400
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300401#define SCA_HEX syscall_arg__scnprintf_hex
402
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300403static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
404 struct syscall_arg *arg)
405{
406 return scnprintf(bf, size, "%d", arg->val);
407}
408
409#define SCA_INT syscall_arg__scnprintf_int
410
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300411static const char *bpf_cmd[] = {
412 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
413 "MAP_GET_NEXT_KEY", "PROG_LOAD",
414};
415static DEFINE_STRARRAY(bpf_cmd);
416
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300417static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
418static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300419
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300420static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
421static DEFINE_STRARRAY(itimers);
422
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300423static const char *keyctl_options[] = {
424 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
425 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
426 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
427 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
428 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
429};
430static DEFINE_STRARRAY(keyctl_options);
431
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300432static const char *whences[] = { "SET", "CUR", "END",
433#ifdef SEEK_DATA
434"DATA",
435#endif
436#ifdef SEEK_HOLE
437"HOLE",
438#endif
439};
440static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300441
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300442static const char *fcntl_cmds[] = {
443 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300444 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
445 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
446 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300447};
448static DEFINE_STRARRAY(fcntl_cmds);
449
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300450static const char *fcntl_linux_specific_cmds[] = {
451 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
452 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
453};
454
455static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
456
457static struct strarray *fcntl_cmds_arrays[] = {
458 &strarray__fcntl_cmds,
459 &strarray__fcntl_linux_specific_cmds,
460};
461
462static DEFINE_STRARRAYS(fcntl_cmds_arrays);
463
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300464static const char *rlimit_resources[] = {
465 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
466 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
467 "RTTIME",
468};
469static DEFINE_STRARRAY(rlimit_resources);
470
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300471static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
472static DEFINE_STRARRAY(sighow);
473
David Ahern4f8c1b72013-09-22 19:45:00 -0600474static const char *clockid[] = {
475 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300476 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
477 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600478};
479static DEFINE_STRARRAY(clockid);
480
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300481static const char *socket_families[] = {
482 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
483 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
484 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
485 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
486 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
487 "ALG", "NFC", "VSOCK",
488};
489static DEFINE_STRARRAY(socket_families);
490
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300491static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
492 struct syscall_arg *arg)
493{
494 size_t printed = 0;
495 int mode = arg->val;
496
497 if (mode == F_OK) /* 0 */
498 return scnprintf(bf, size, "F");
499#define P_MODE(n) \
500 if (mode & n##_OK) { \
501 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
502 mode &= ~n##_OK; \
503 }
504
505 P_MODE(R);
506 P_MODE(W);
507 P_MODE(X);
508#undef P_MODE
509
510 if (mode)
511 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
512
513 return printed;
514}
515
516#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
517
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300518static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
519 struct syscall_arg *arg);
520
521#define SCA_FILENAME syscall_arg__scnprintf_filename
522
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300523static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
524 struct syscall_arg *arg)
525{
526 int printed = 0, flags = arg->val;
527
528#define P_FLAG(n) \
529 if (flags & O_##n) { \
530 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
531 flags &= ~O_##n; \
532 }
533
534 P_FLAG(CLOEXEC);
535 P_FLAG(NONBLOCK);
536#undef P_FLAG
537
538 if (flags)
539 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
540
541 return printed;
542}
543
544#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
545
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300546#if defined(__i386__) || defined(__x86_64__)
547/*
548 * FIXME: Make this available to all arches.
549 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300550#define TCGETS 0x5401
551
552static const char *tioctls[] = {
553 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
554 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
555 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
556 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
557 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
558 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
559 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
560 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
561 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
562 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
563 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
564 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
565 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
566 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
567 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
568};
569
570static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300571#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300572
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300573#ifndef GRND_NONBLOCK
574#define GRND_NONBLOCK 0x0001
575#endif
576#ifndef GRND_RANDOM
577#define GRND_RANDOM 0x0002
578#endif
579
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300580static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
581 struct syscall_arg *arg)
582{
583 int printed = 0, flags = arg->val;
584
585#define P_FLAG(n) \
586 if (flags & GRND_##n) { \
587 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
588 flags &= ~GRND_##n; \
589 }
590
591 P_FLAG(RANDOM);
592 P_FLAG(NONBLOCK);
593#undef P_FLAG
594
595 if (flags)
596 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
597
598 return printed;
599}
600
601#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
602
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300603#define STRARRAY(arg, name, array) \
604 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
605 .arg_parm = { [arg] = &strarray__##array, }
606
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300607#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300608#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300609#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300610#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300611#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300612#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300613#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300614#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300615#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300616#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300617#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300618#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300619#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300620#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300621
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300622static struct syscall_fmt {
623 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300624 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300625 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300626 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300627 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300628 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300629 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300630 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300631} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300632 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300633 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300634 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300635 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300636 { .name = "brk", .hexret = true,
637 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300638 { .name = "chdir", .errmsg = true, },
639 { .name = "chmod", .errmsg = true, },
640 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600641 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300642 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300643 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300644 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300645 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300646 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300647 { .name = "dup", .errmsg = true, },
648 { .name = "dup2", .errmsg = true, },
649 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300650 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300651 { .name = "eventfd2", .errmsg = true,
652 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300653 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300654 { .name = "fadvise64", .errmsg = true, },
655 { .name = "fallocate", .errmsg = true, },
656 { .name = "fchdir", .errmsg = true, },
657 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300658 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300659 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300660 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300661 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300662 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300663 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300664 .arg_scnprintf = { [1] = SCA_STRARRAYS, /* cmd */ },
665 .arg_parm = { [1] = &strarrays__fcntl_cmds_arrays, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300666 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300667 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300668 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
669 { .name = "fsetxattr", .errmsg = true, },
670 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300671 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300672 { .name = "fstatfs", .errmsg = true, },
673 { .name = "fsync", .errmsg = true, },
674 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300675 { .name = "futex", .errmsg = true,
676 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300677 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300678 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300679 { .name = "getdents", .errmsg = true, },
680 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300681 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300682 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300683 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300684 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300685 { .name = "getrandom", .errmsg = true,
686 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300687 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300688 { .name = "getxattr", .errmsg = true, },
689 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300690 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300691 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300692#if defined(__i386__) || defined(__x86_64__)
693/*
694 * FIXME: Make this available to all arches.
695 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300696 [1] = SCA_STRHEXARRAY, /* cmd */
697 [2] = SCA_HEX, /* arg */ },
698 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300699#else
700 [2] = SCA_HEX, /* arg */ }, },
701#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300702 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300703 { .name = "kill", .errmsg = true,
704 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300705 { .name = "lchown", .errmsg = true, },
706 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300707 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300708 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300709 { .name = "listxattr", .errmsg = true, },
710 { .name = "llistxattr", .errmsg = true, },
711 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300712 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300713 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300714 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300715 { .name = "lsetxattr", .errmsg = true, },
716 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
717 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300718 { .name = "madvise", .errmsg = true,
719 .arg_scnprintf = { [0] = SCA_HEX, /* start */
720 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300721 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300722 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300723 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
724 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300725 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300726 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300727 { .name = "mlock", .errmsg = true,
728 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
729 { .name = "mlockall", .errmsg = true,
730 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300731 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200732/* The standard mmap maps to old_mmap on s390x */
733#if defined(__s390x__)
734 .alias = "old_mmap",
735#endif
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300736 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300737 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300738 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300739 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300740 .arg_scnprintf = { [0] = SCA_HEX, /* start */
741 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300742 { .name = "mq_unlink", .errmsg = true,
743 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300744 { .name = "mremap", .hexret = true,
745 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300746 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300747 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300748 { .name = "munlock", .errmsg = true,
749 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300750 { .name = "munmap", .errmsg = true,
751 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300752 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300753 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300754 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300755 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300756 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300757 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300758 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300759 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
760 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300761 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300762 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
763 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300764 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300765 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300766 [3] = SCA_FD, /* group_fd */
767 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300768 { .name = "pipe2", .errmsg = true,
769 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300770 { .name = "poll", .errmsg = true, .timeout = true, },
771 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300772 { .name = "pread", .errmsg = true, .alias = "pread64", },
773 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300774 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300775 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
776 { .name = "pwritev", .errmsg = true, },
777 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300778 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300779 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300780 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300781 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300782 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300783 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300784 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300785 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300786 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300787 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300788 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300789 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300790 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300791 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300792 { .name = "rt_sigaction", .errmsg = true,
793 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300794 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300795 { .name = "rt_sigqueueinfo", .errmsg = true,
796 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
797 { .name = "rt_tgsigqueueinfo", .errmsg = true,
798 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300799 { .name = "sched_getattr", .errmsg = true, },
800 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300801 { .name = "sched_setscheduler", .errmsg = true,
802 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300803 { .name = "seccomp", .errmsg = true,
804 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
805 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300806 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300807 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300808 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300809 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300810 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300811 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300812 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300813 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300814 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300815 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300816 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300817 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300818 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300819 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300820 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
821 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300822 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300823 { .name = "socketpair", .errmsg = true,
824 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
825 [1] = SCA_SK_TYPE, /* type */ },
826 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300827 { .name = "stat", .errmsg = true, .alias = "newstat", },
828 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300829 { .name = "statx", .errmsg = true,
830 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
831 [2] = SCA_STATX_FLAGS, /* flags */
832 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300833 { .name = "swapoff", .errmsg = true,
834 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
835 { .name = "swapon", .errmsg = true,
836 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300837 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300838 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300839 { .name = "tgkill", .errmsg = true,
840 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
841 { .name = "tkill", .errmsg = true,
842 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300843 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300844 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300845 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300846 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
847 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300848 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300849 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
850 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300851 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300852 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300853 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300854 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300855 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300856 { .name = "write", .errmsg = true, },
857 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300858};
859
860static int syscall_fmt__cmp(const void *name, const void *fmtp)
861{
862 const struct syscall_fmt *fmt = fmtp;
863 return strcmp(name, fmt->name);
864}
865
866static struct syscall_fmt *syscall_fmt__find(const char *name)
867{
868 const int nmemb = ARRAY_SIZE(syscall_fmts);
869 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
870}
871
872struct syscall {
873 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300874 int nr_args;
875 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300876 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300877 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300878 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300879 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300880 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300881};
882
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300883/*
884 * We need to have this 'calculated' boolean because in some cases we really
885 * don't know what is the duration of a syscall, for instance, when we start
886 * a session and some threads are waiting for a syscall to finish, say 'poll',
887 * in which case all we can do is to print "( ? ) for duration and for the
888 * start timestamp.
889 */
890static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200891{
892 double duration = (double)t / NSEC_PER_MSEC;
893 size_t printed = fprintf(fp, "(");
894
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300895 if (!calculated)
896 printed += fprintf(fp, " ? ");
897 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200898 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
899 else if (duration >= 0.01)
900 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
901 else
902 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300903 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200904}
905
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300906/**
907 * filename.ptr: The filename char pointer that will be vfs_getname'd
908 * filename.entry_str_pos: Where to insert the string translated from
909 * filename.ptr by the vfs_getname tracepoint/kprobe.
910 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300911struct thread_trace {
912 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300913 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300914 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400915 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300916 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300917 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300918 struct {
919 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300920 short int entry_str_pos;
921 bool pending_open;
922 unsigned int namelen;
923 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300924 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300925 struct {
926 int max;
927 char **table;
928 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600929
930 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300931};
932
933static struct thread_trace *thread_trace__new(void)
934{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300935 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
936
937 if (ttrace)
938 ttrace->paths.max = -1;
939
David Ahernbf2575c2013-10-08 21:26:53 -0600940 ttrace->syscall_stats = intlist__new(NULL);
941
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300942 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300943}
944
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300945static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300946{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300947 struct thread_trace *ttrace;
948
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300949 if (thread == NULL)
950 goto fail;
951
Namhyung Kim89dceb22014-10-06 09:46:03 +0900952 if (thread__priv(thread) == NULL)
953 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300954
Namhyung Kim89dceb22014-10-06 09:46:03 +0900955 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300956 goto fail;
957
Namhyung Kim89dceb22014-10-06 09:46:03 +0900958 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300959 ++ttrace->nr_events;
960
961 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300962fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300963 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300964 "WARNING: not enough memory, dropping samples!\n");
965 return NULL;
966}
967
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400968#define TRACE_PFMAJ (1 << 0)
969#define TRACE_PFMIN (1 << 1)
970
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300971static const size_t trace__entry_str_size = 2048;
972
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300973static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300974{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900975 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300976
977 if (fd > ttrace->paths.max) {
978 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
979
980 if (npath == NULL)
981 return -1;
982
983 if (ttrace->paths.max != -1) {
984 memset(npath + ttrace->paths.max + 1, 0,
985 (fd - ttrace->paths.max) * sizeof(char *));
986 } else {
987 memset(npath, 0, (fd + 1) * sizeof(char *));
988 }
989
990 ttrace->paths.table = npath;
991 ttrace->paths.max = fd;
992 }
993
994 ttrace->paths.table[fd] = strdup(pathname);
995
996 return ttrace->paths.table[fd] != NULL ? 0 : -1;
997}
998
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300999static int thread__read_fd_path(struct thread *thread, int fd)
1000{
1001 char linkname[PATH_MAX], pathname[PATH_MAX];
1002 struct stat st;
1003 int ret;
1004
1005 if (thread->pid_ == thread->tid) {
1006 scnprintf(linkname, sizeof(linkname),
1007 "/proc/%d/fd/%d", thread->pid_, fd);
1008 } else {
1009 scnprintf(linkname, sizeof(linkname),
1010 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1011 }
1012
1013 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1014 return -1;
1015
1016 ret = readlink(linkname, pathname, sizeof(pathname));
1017
1018 if (ret < 0 || ret > st.st_size)
1019 return -1;
1020
1021 pathname[ret] = '\0';
1022 return trace__set_fd_pathname(thread, fd, pathname);
1023}
1024
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001025static const char *thread__fd_path(struct thread *thread, int fd,
1026 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001028 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001029
1030 if (ttrace == NULL)
1031 return NULL;
1032
1033 if (fd < 0)
1034 return NULL;
1035
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001036 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001037 if (!trace->live)
1038 return NULL;
1039 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001040 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001041 return NULL;
1042 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001043
1044 return ttrace->paths.table[fd];
1045}
1046
1047static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1048 struct syscall_arg *arg)
1049{
1050 int fd = arg->val;
1051 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001052 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001053
1054 if (path)
1055 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1056
1057 return printed;
1058}
1059
1060static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1061 struct syscall_arg *arg)
1062{
1063 int fd = arg->val;
1064 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001065 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001066
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001067 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1068 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001069
1070 return printed;
1071}
1072
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001073static void thread__set_filename_pos(struct thread *thread, const char *bf,
1074 unsigned long ptr)
1075{
1076 struct thread_trace *ttrace = thread__priv(thread);
1077
1078 ttrace->filename.ptr = ptr;
1079 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1080}
1081
1082static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1083 struct syscall_arg *arg)
1084{
1085 unsigned long ptr = arg->val;
1086
1087 if (!arg->trace->vfs_getname)
1088 return scnprintf(bf, size, "%#x", ptr);
1089
1090 thread__set_filename_pos(arg->thread, bf, ptr);
1091 return 0;
1092}
1093
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001094static bool trace__filter_duration(struct trace *trace, double t)
1095{
1096 return t < (trace->duration_filter * NSEC_PER_MSEC);
1097}
1098
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001099static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100{
1101 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1102
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001103 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104}
1105
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001106/*
1107 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1108 * using ttrace->entry_time for a thread that receives a sys_exit without
1109 * first having received a sys_enter ("poll" issued before tracing session
1110 * starts, lost sys_enter exit due to ring buffer overflow).
1111 */
1112static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1113{
1114 if (tstamp > 0)
1115 return __trace__fprintf_tstamp(trace, tstamp, fp);
1116
1117 return fprintf(fp, " ? ");
1118}
1119
Namhyung Kimf15eb532012-10-05 14:02:16 +09001120static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001121static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001122
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001123static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001124{
1125 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001126 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001127}
1128
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001129static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001130 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131{
1132 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001133 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001134
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001135 if (trace->multiple_threads) {
1136 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001137 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001138 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001139 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001140
1141 return printed;
1142}
1143
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001144static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001145 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146{
1147 int ret = 0;
1148
1149 switch (event->header.type) {
1150 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001151 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001152 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001153 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001154 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001156 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157 break;
1158 }
1159
1160 return ret;
1161}
1162
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001163static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001164 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001165 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001166 struct machine *machine)
1167{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001168 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001169 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001170}
1171
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001172static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1173{
1174 struct machine *machine = vmachine;
1175
1176 if (machine->kptr_restrict_warned)
1177 return NULL;
1178
1179 if (symbol_conf.kptr_restrict) {
1180 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1181 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1182 "Kernel samples will not be resolved.\n");
1183 machine->kptr_restrict_warned = true;
1184 return NULL;
1185 }
1186
1187 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1188}
1189
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001190static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1191{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001192 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001193
1194 if (err)
1195 return err;
1196
David Ahern8fb598e2013-09-28 13:13:00 -06001197 trace->host = machine__new_host();
1198 if (trace->host == NULL)
1199 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001200
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001201 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001202 return -errno;
1203
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001204 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001205 evlist->threads, trace__tool_process, false,
1206 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001207 if (err)
1208 symbol__exit();
1209
1210 return err;
1211}
1212
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001213static int syscall__set_arg_fmts(struct syscall *sc)
1214{
1215 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001216 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001217
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001218 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001219 if (sc->arg_scnprintf == NULL)
1220 return -1;
1221
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001222 if (sc->fmt)
1223 sc->arg_parm = sc->fmt->arg_parm;
1224
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001225 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001226 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1227 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001228 else if (strcmp(field->type, "const char *") == 0 &&
1229 (strcmp(field->name, "filename") == 0 ||
1230 strcmp(field->name, "path") == 0 ||
1231 strcmp(field->name, "pathname") == 0))
1232 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001233 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001234 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001235 else if (strcmp(field->type, "pid_t") == 0)
1236 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001237 else if (strcmp(field->type, "umode_t") == 0)
1238 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001239 else if ((strcmp(field->type, "int") == 0 ||
1240 strcmp(field->type, "unsigned int") == 0 ||
1241 strcmp(field->type, "long") == 0) &&
1242 (len = strlen(field->name)) >= 2 &&
1243 strcmp(field->name + len - 2, "fd") == 0) {
1244 /*
1245 * /sys/kernel/tracing/events/syscalls/sys_enter*
1246 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1247 * 65 int
1248 * 23 unsigned int
1249 * 7 unsigned long
1250 */
1251 sc->arg_scnprintf[idx] = SCA_FD;
1252 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001253 ++idx;
1254 }
1255
1256 return 0;
1257}
1258
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001259static int trace__read_syscall_info(struct trace *trace, int id)
1260{
1261 char tp_name[128];
1262 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001263 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001264
1265 if (name == NULL)
1266 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001267
1268 if (id > trace->syscalls.max) {
1269 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1270
1271 if (nsyscalls == NULL)
1272 return -1;
1273
1274 if (trace->syscalls.max != -1) {
1275 memset(nsyscalls + trace->syscalls.max + 1, 0,
1276 (id - trace->syscalls.max) * sizeof(*sc));
1277 } else {
1278 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1279 }
1280
1281 trace->syscalls.table = nsyscalls;
1282 trace->syscalls.max = id;
1283 }
1284
1285 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001286 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001287
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001288 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001289
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001290 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001291 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001292
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001293 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001294 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001295 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001296 }
1297
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001298 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001299 return -1;
1300
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001301 sc->args = sc->tp_format->format.fields;
1302 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001303 /*
1304 * We need to check and discard the first variable '__syscall_nr'
1305 * or 'nr' that mean the syscall number. It is needless here.
1306 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1307 */
1308 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001309 sc->args = sc->args->next;
1310 --sc->nr_args;
1311 }
1312
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001313 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1314
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001315 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001316}
1317
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001318static int trace__validate_ev_qualifier(struct trace *trace)
1319{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001320 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001321 struct str_node *pos;
1322
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001323 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1324 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1325 sizeof(trace->ev_qualifier_ids.entries[0]));
1326
1327 if (trace->ev_qualifier_ids.entries == NULL) {
1328 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1329 trace->output);
1330 err = -EINVAL;
1331 goto out;
1332 }
1333
1334 i = 0;
1335
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001336 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001337 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001338 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001339
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001340 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001341 if (err == 0) {
1342 fputs("Error:\tInvalid syscall ", trace->output);
1343 err = -EINVAL;
1344 } else {
1345 fputs(", ", trace->output);
1346 }
1347
1348 fputs(sc, trace->output);
1349 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001350
1351 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001352 }
1353
1354 if (err < 0) {
1355 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1356 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001357 zfree(&trace->ev_qualifier_ids.entries);
1358 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001359 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001360out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001361 return err;
1362}
1363
David Ahern55d43bca2015-02-19 15:00:22 -05001364/*
1365 * args is to be interpreted as a series of longs but we need to handle
1366 * 8-byte unaligned accesses. args points to raw_data within the event
1367 * and raw_data is guaranteed to be 8-byte unaligned because it is
1368 * preceded by raw_size which is a u32. So we need to copy args to a temp
1369 * variable to read it. Most notably this avoids extended load instructions
1370 * on unaligned addresses
1371 */
1372
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001373static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001374 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001375 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001376{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001377 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001378 unsigned char *p;
1379 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001380
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001381 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001382 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001383 u8 bit = 1;
1384 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001385 .idx = 0,
1386 .mask = 0,
1387 .trace = trace,
1388 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001389 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001390
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001391 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001392 field = field->next, ++arg.idx, bit <<= 1) {
1393 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001394 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001395
1396 /* special care for unaligned accesses */
1397 p = args + sizeof(unsigned long) * arg.idx;
1398 memcpy(&val, p, sizeof(val));
1399
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001400 /*
1401 * Suppress this argument if its value is zero and
1402 * and we don't have a string associated in an
1403 * strarray for it.
1404 */
David Ahern55d43bca2015-02-19 15:00:22 -05001405 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001406 !(sc->arg_scnprintf &&
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -03001407 (sc->arg_scnprintf[arg.idx] == SCA_STRARRAY ||
1408 sc->arg_scnprintf[arg.idx] == SCA_STRARRAYS) &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001409 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001410 continue;
1411
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001412 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001413 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001414 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001415 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001416 if (sc->arg_parm)
1417 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001418 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1419 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001420 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001421 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001422 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001423 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001424 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001425 } else if (IS_ERR(sc->tp_format)) {
1426 /*
1427 * If we managed to read the tracepoint /format file, then we
1428 * may end up not having any args, like with gettid(), so only
1429 * print the raw args when we didn't manage to read it.
1430 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001431 int i = 0;
1432
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001433 while (i < 6) {
David Ahern55d43bca2015-02-19 15:00:22 -05001434 /* special care for unaligned accesses */
1435 p = args + sizeof(unsigned long) * i;
1436 memcpy(&val, p, sizeof(val));
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001437 printed += scnprintf(bf + printed, size - printed,
1438 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001439 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001440 ++i;
1441 }
1442 }
1443
1444 return printed;
1445}
1446
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001447typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001448 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001449 struct perf_sample *sample);
1450
1451static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001452 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001453{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001454
1455 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001456
1457 /*
1458 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1459 * before that, leaving at a higher verbosity level till that is
1460 * explained. Reproduced with plain ftrace with:
1461 *
1462 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1463 * grep "NR -1 " /t/trace_pipe
1464 *
1465 * After generating some load on the machine.
1466 */
1467 if (verbose > 1) {
1468 static u64 n;
1469 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1470 id, perf_evsel__name(evsel), ++n);
1471 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001472 return NULL;
1473 }
1474
1475 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1476 trace__read_syscall_info(trace, id))
1477 goto out_cant_read;
1478
1479 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1480 goto out_cant_read;
1481
1482 return &trace->syscalls.table[id];
1483
1484out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001485 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001486 fprintf(trace->output, "Problems reading syscall %d", id);
1487 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1488 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1489 fputs(" information\n", trace->output);
1490 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001491 return NULL;
1492}
1493
David Ahernbf2575c2013-10-08 21:26:53 -06001494static void thread__update_stats(struct thread_trace *ttrace,
1495 int id, struct perf_sample *sample)
1496{
1497 struct int_node *inode;
1498 struct stats *stats;
1499 u64 duration = 0;
1500
1501 inode = intlist__findnew(ttrace->syscall_stats, id);
1502 if (inode == NULL)
1503 return;
1504
1505 stats = inode->priv;
1506 if (stats == NULL) {
1507 stats = malloc(sizeof(struct stats));
1508 if (stats == NULL)
1509 return;
1510 init_stats(stats);
1511 inode->priv = stats;
1512 }
1513
1514 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1515 duration = sample->time - ttrace->entry_time;
1516
1517 update_stats(stats, duration);
1518}
1519
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001520static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1521{
1522 struct thread_trace *ttrace;
1523 u64 duration;
1524 size_t printed;
1525
1526 if (trace->current == NULL)
1527 return 0;
1528
1529 ttrace = thread__priv(trace->current);
1530
1531 if (!ttrace->entry_pending)
1532 return 0;
1533
1534 duration = sample->time - ttrace->entry_time;
1535
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001536 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001537 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1538 ttrace->entry_pending = false;
1539
1540 return printed;
1541}
1542
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001543static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001544 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001545 struct perf_sample *sample)
1546{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001547 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001548 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001549 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001550 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001551 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001552 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001553 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001554
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001555 if (sc == NULL)
1556 return -1;
1557
David Ahern8fb598e2013-09-28 13:13:00 -06001558 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001559 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001560 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001561 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001562
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001563 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001564
1565 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001566 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001567 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001568 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001569 }
1570
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001571 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001572 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001573
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001574 ttrace->entry_time = sample->time;
1575 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001576 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001577
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001578 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001579 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001580
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001581 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001582 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001583 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001584 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001585 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001586 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001587 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001588 /* See trace__vfs_getname & trace__sys_exit */
1589 ttrace->filename.pending_open = false;
1590 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001591
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001592 if (trace->current != thread) {
1593 thread__put(trace->current);
1594 trace->current = thread__get(thread);
1595 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001596 err = 0;
1597out_put:
1598 thread__put(thread);
1599 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001600}
1601
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001602static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1603 struct perf_sample *sample,
1604 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001605{
1606 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001607
1608 if (machine__resolve(trace->host, &al, sample) < 0 ||
1609 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1610 return -1;
1611
1612 return 0;
1613}
1614
1615static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1616{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001617 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001618 const unsigned int print_opts = EVSEL__PRINT_SYM |
1619 EVSEL__PRINT_DSO |
1620 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001621
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001622 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001623}
1624
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001625static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001626 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001627 struct perf_sample *sample)
1628{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001629 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001630 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001631 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001632 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001633 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001634 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001635 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001636
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001637 if (sc == NULL)
1638 return -1;
1639
David Ahern8fb598e2013-09-28 13:13:00 -06001640 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001641 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001642 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001643 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001644
David Ahernbf2575c2013-10-08 21:26:53 -06001645 if (trace->summary)
1646 thread__update_stats(ttrace, id, sample);
1647
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001648 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001649
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001650 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001651 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1652 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001653 ++trace->stats.vfs_getname;
1654 }
1655
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001656 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001657 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001658 if (trace__filter_duration(trace, duration))
1659 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001660 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001661 } else if (trace->duration_filter)
1662 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001663
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001664 if (sample->callchain) {
1665 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1666 if (callchain_ret == 0) {
1667 if (callchain_cursor.nr < trace->min_stack)
1668 goto out;
1669 callchain_ret = 1;
1670 }
1671 }
1672
David Ahernfd2eaba2013-11-12 09:31:15 -07001673 if (trace->summary_only)
1674 goto out;
1675
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001676 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001677
1678 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001679 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001681 fprintf(trace->output, " ... [");
1682 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1683 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001684 }
1685
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001686 if (sc->fmt == NULL) {
1687signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001688 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001689 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001690 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001691 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001692 *e = audit_errno_to_name(-ret);
1693
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001694 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001695 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001696 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001697 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001698 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001699 else if (sc->fmt->errpid) {
1700 struct thread *child = machine__find_thread(trace->host, ret, ret);
1701
1702 if (child != NULL) {
1703 fprintf(trace->output, ") = %ld", ret);
1704 if (child->comm_set)
1705 fprintf(trace->output, " (%s)", thread__comm_str(child));
1706 thread__put(child);
1707 }
1708 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001709 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001710
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001711 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001712
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001713 if (callchain_ret > 0)
1714 trace__fprintf_callchain(trace, sample);
1715 else if (callchain_ret < 0)
1716 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001717out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001718 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001719 err = 0;
1720out_put:
1721 thread__put(thread);
1722 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001723}
1724
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001725static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001726 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001727 struct perf_sample *sample)
1728{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001729 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1730 struct thread_trace *ttrace;
1731 size_t filename_len, entry_str_len, to_move;
1732 ssize_t remaining_space;
1733 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001734 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001735
1736 if (!thread)
1737 goto out;
1738
1739 ttrace = thread__priv(thread);
1740 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001741 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001742
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001743 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001744 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001745 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001746
1747 if (ttrace->filename.namelen < filename_len) {
1748 char *f = realloc(ttrace->filename.name, filename_len + 1);
1749
1750 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001751 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001752
1753 ttrace->filename.namelen = filename_len;
1754 ttrace->filename.name = f;
1755 }
1756
1757 strcpy(ttrace->filename.name, filename);
1758 ttrace->filename.pending_open = true;
1759
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001760 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001761 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001762
1763 entry_str_len = strlen(ttrace->entry_str);
1764 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1765 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001766 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001767
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001768 if (filename_len > (size_t)remaining_space) {
1769 filename += filename_len - remaining_space;
1770 filename_len = remaining_space;
1771 }
1772
1773 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1774 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1775 memmove(pos + filename_len, pos, to_move);
1776 memcpy(pos, filename, filename_len);
1777
1778 ttrace->filename.ptr = 0;
1779 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001780out_put:
1781 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001782out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001783 return 0;
1784}
1785
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001786static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001787 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001788 struct perf_sample *sample)
1789{
1790 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1791 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001792 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001793 sample->pid,
1794 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001795 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001796
1797 if (ttrace == NULL)
1798 goto out_dump;
1799
1800 ttrace->runtime_ms += runtime_ms;
1801 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001802out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001803 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001804 return 0;
1805
1806out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001807 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001808 evsel->name,
1809 perf_evsel__strval(evsel, sample, "comm"),
1810 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1811 runtime,
1812 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001813 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001814}
1815
Wang Nan1d6c9402016-02-26 09:31:55 +00001816static void bpf_output__printer(enum binary_printer_ops op,
1817 unsigned int val, void *extra)
1818{
1819 FILE *output = extra;
1820 unsigned char ch = (unsigned char)val;
1821
1822 switch (op) {
1823 case BINARY_PRINT_CHAR_DATA:
1824 fprintf(output, "%c", isprint(ch) ? ch : '.');
1825 break;
1826 case BINARY_PRINT_DATA_BEGIN:
1827 case BINARY_PRINT_LINE_BEGIN:
1828 case BINARY_PRINT_ADDR:
1829 case BINARY_PRINT_NUM_DATA:
1830 case BINARY_PRINT_NUM_PAD:
1831 case BINARY_PRINT_SEP:
1832 case BINARY_PRINT_CHAR_PAD:
1833 case BINARY_PRINT_LINE_END:
1834 case BINARY_PRINT_DATA_END:
1835 default:
1836 break;
1837 }
1838}
1839
1840static void bpf_output__fprintf(struct trace *trace,
1841 struct perf_sample *sample)
1842{
1843 print_binary(sample->raw_data, sample->raw_size, 8,
1844 bpf_output__printer, trace->output);
1845}
1846
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001847static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1848 union perf_event *event __maybe_unused,
1849 struct perf_sample *sample)
1850{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001851 int callchain_ret = 0;
1852
1853 if (sample->callchain) {
1854 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1855 if (callchain_ret == 0) {
1856 if (callchain_cursor.nr < trace->min_stack)
1857 goto out;
1858 callchain_ret = 1;
1859 }
1860 }
1861
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001862 trace__printf_interrupted_entry(trace, sample);
1863 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001864
1865 if (trace->trace_syscalls)
1866 fprintf(trace->output, "( ): ");
1867
1868 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001869
Wang Nan1d6c9402016-02-26 09:31:55 +00001870 if (perf_evsel__is_bpf_output(evsel)) {
1871 bpf_output__fprintf(trace, sample);
1872 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001873 event_format__fprintf(evsel->tp_format, sample->cpu,
1874 sample->raw_data, sample->raw_size,
1875 trace->output);
1876 }
1877
1878 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001879
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001880 if (callchain_ret > 0)
1881 trace__fprintf_callchain(trace, sample);
1882 else if (callchain_ret < 0)
1883 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1884out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001885 return 0;
1886}
1887
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001888static void print_location(FILE *f, struct perf_sample *sample,
1889 struct addr_location *al,
1890 bool print_dso, bool print_sym)
1891{
1892
Namhyung Kimbb963e12017-02-17 17:17:38 +09001893 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001894 fprintf(f, "%s@", al->map->dso->long_name);
1895
Namhyung Kimbb963e12017-02-17 17:17:38 +09001896 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001897 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001898 al->addr - al->sym->start);
1899 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001900 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001901 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001902 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001903}
1904
1905static int trace__pgfault(struct trace *trace,
1906 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001907 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001908 struct perf_sample *sample)
1909{
1910 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001911 struct addr_location al;
1912 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001913 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001914 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001915 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001916
1917 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001918
1919 if (sample->callchain) {
1920 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1921 if (callchain_ret == 0) {
1922 if (callchain_cursor.nr < trace->min_stack)
1923 goto out_put;
1924 callchain_ret = 1;
1925 }
1926 }
1927
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001928 ttrace = thread__trace(thread, trace->output);
1929 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001930 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001931
1932 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1933 ttrace->pfmaj++;
1934 else
1935 ttrace->pfmin++;
1936
1937 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001938 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001939
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001940 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001941 sample->ip, &al);
1942
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001943 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001944
1945 fprintf(trace->output, "%sfault [",
1946 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1947 "maj" : "min");
1948
1949 print_location(trace->output, sample, &al, false, true);
1950
1951 fprintf(trace->output, "] => ");
1952
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001953 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001954 sample->addr, &al);
1955
1956 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001957 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001958 MAP__FUNCTION, sample->addr, &al);
1959
1960 if (al.map)
1961 map_type = 'x';
1962 else
1963 map_type = '?';
1964 }
1965
1966 print_location(trace->output, sample, &al, true, false);
1967
1968 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001969
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001970 if (callchain_ret > 0)
1971 trace__fprintf_callchain(trace, sample);
1972 else if (callchain_ret < 0)
1973 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001974out:
1975 err = 0;
1976out_put:
1977 thread__put(thread);
1978 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001979}
1980
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001981static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001982 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001983 struct perf_sample *sample)
1984{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001985 /*
1986 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1987 * and don't use sample->time unconditionally, we may end up having
1988 * some other event in the future without PERF_SAMPLE_TIME for good
1989 * reason, i.e. we may not be interested in its timestamps, just in
1990 * it taking place, picking some piece of information when it
1991 * appears in our event stream (vfs_getname comes to mind).
1992 */
1993 if (trace->base_time == 0 && !trace->full_time &&
1994 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001995 trace->base_time = sample->time;
1996}
1997
David Ahern6810fc92013-08-28 22:29:52 -06001998static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001999 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002000 struct perf_sample *sample,
2001 struct perf_evsel *evsel,
2002 struct machine *machine __maybe_unused)
2003{
2004 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002005 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002006 int err = 0;
2007
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002008 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002009
David Ahernaa07df62016-11-25 09:29:52 -07002010 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2011 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002012 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002013
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002014 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002015
David Ahern31605652013-12-04 19:41:41 -07002016 if (handler) {
2017 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002018 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002019 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002020out:
2021 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002022 return err;
2023}
2024
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002025static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002026{
2027 unsigned int rec_argc, i, j;
2028 const char **rec_argv;
2029 const char * const record_args[] = {
2030 "record",
2031 "-R",
2032 "-m", "1024",
2033 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002034 };
2035
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002036 const char * const sc_args[] = { "-e", };
2037 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2038 const char * const majpf_args[] = { "-e", "major-faults" };
2039 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2040 const char * const minpf_args[] = { "-e", "minor-faults" };
2041 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2042
David Ahern9aca7f12013-12-04 19:41:39 -07002043 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002044 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2045 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002046 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2047
2048 if (rec_argv == NULL)
2049 return -ENOMEM;
2050
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002051 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002052 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002053 rec_argv[j++] = record_args[i];
2054
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002055 if (trace->trace_syscalls) {
2056 for (i = 0; i < sc_args_nr; i++)
2057 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002058
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002059 /* event string may be different for older kernels - e.g., RHEL6 */
2060 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2061 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2062 else if (is_valid_tracepoint("syscalls:sys_enter"))
2063 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2064 else {
2065 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2066 return -1;
2067 }
David Ahern9aca7f12013-12-04 19:41:39 -07002068 }
David Ahern9aca7f12013-12-04 19:41:39 -07002069
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002070 if (trace->trace_pgfaults & TRACE_PFMAJ)
2071 for (i = 0; i < majpf_args_nr; i++)
2072 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002073
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002074 if (trace->trace_pgfaults & TRACE_PFMIN)
2075 for (i = 0; i < minpf_args_nr; i++)
2076 rec_argv[j++] = minpf_args[i];
2077
2078 for (i = 0; i < (unsigned int)argc; i++)
2079 rec_argv[j++] = argv[i];
2080
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002081 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002082}
2083
David Ahernbf2575c2013-10-08 21:26:53 -06002084static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2085
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002086static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002087{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002088 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002089
2090 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002091 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002092
2093 if (perf_evsel__field(evsel, "pathname") == NULL) {
2094 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002095 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002096 }
2097
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002098 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002099 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002100 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002101}
2102
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002103static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002104{
2105 struct perf_evsel *evsel;
2106 struct perf_event_attr attr = {
2107 .type = PERF_TYPE_SOFTWARE,
2108 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002109 };
2110
2111 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002112 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002113
2114 event_attr_init(&attr);
2115
2116 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002117 if (evsel)
2118 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002119
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002120 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002121}
2122
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002123static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2124{
2125 const u32 type = event->header.type;
2126 struct perf_evsel *evsel;
2127
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002128 if (type != PERF_RECORD_SAMPLE) {
2129 trace__process_event(trace, trace->host, event, sample);
2130 return;
2131 }
2132
2133 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2134 if (evsel == NULL) {
2135 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2136 return;
2137 }
2138
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002139 trace__set_base_time(trace, evsel, sample);
2140
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002141 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2142 sample->raw_data == NULL) {
2143 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2144 perf_evsel__name(evsel), sample->tid,
2145 sample->cpu, sample->raw_size);
2146 } else {
2147 tracepoint_handler handler = evsel->handler;
2148 handler(trace, evsel, event, sample);
2149 }
2150}
2151
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002152static int trace__add_syscall_newtp(struct trace *trace)
2153{
2154 int ret = -1;
2155 struct perf_evlist *evlist = trace->evlist;
2156 struct perf_evsel *sys_enter, *sys_exit;
2157
2158 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2159 if (sys_enter == NULL)
2160 goto out;
2161
2162 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2163 goto out_delete_sys_enter;
2164
2165 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2166 if (sys_exit == NULL)
2167 goto out_delete_sys_enter;
2168
2169 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2170 goto out_delete_sys_exit;
2171
2172 perf_evlist__add(evlist, sys_enter);
2173 perf_evlist__add(evlist, sys_exit);
2174
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002175 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002176 /*
2177 * We're interested only in the user space callchain
2178 * leading to the syscall, allow overriding that for
2179 * debugging reasons using --kernel_syscall_callchains
2180 */
2181 sys_exit->attr.exclude_callchain_kernel = 1;
2182 }
2183
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002184 trace->syscalls.events.sys_enter = sys_enter;
2185 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002186
2187 ret = 0;
2188out:
2189 return ret;
2190
2191out_delete_sys_exit:
2192 perf_evsel__delete_priv(sys_exit);
2193out_delete_sys_enter:
2194 perf_evsel__delete_priv(sys_enter);
2195 goto out;
2196}
2197
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002198static int trace__set_ev_qualifier_filter(struct trace *trace)
2199{
2200 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002201 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002202 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2203 trace->ev_qualifier_ids.nr,
2204 trace->ev_qualifier_ids.entries);
2205
2206 if (filter == NULL)
2207 goto out_enomem;
2208
Mathieu Poirier3541c032016-09-16 08:44:04 -06002209 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2210 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002211 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002212 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002213 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002214
2215 free(filter);
2216out:
2217 return err;
2218out_enomem:
2219 errno = ENOMEM;
2220 goto out;
2221}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002222
Namhyung Kimf15eb532012-10-05 14:02:16 +09002223static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002224{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002225 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002226 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002227 int err = -1, i;
2228 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002229 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002230 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002231
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002232 trace->live = true;
2233
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002234 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002235 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002236
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002237 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002238 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002239
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002240 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2241 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2242 if (pgfault_maj == NULL)
2243 goto out_error_mem;
2244 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002245 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002246
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002247 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2248 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2249 if (pgfault_min == NULL)
2250 goto out_error_mem;
2251 perf_evlist__add(evlist, pgfault_min);
2252 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002253
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002254 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002255 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2256 trace__sched_stat_runtime))
2257 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002258
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002259 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2260 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002261 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002262 goto out_delete_evlist;
2263 }
2264
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002265 err = trace__symbols_init(trace, evlist);
2266 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002267 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002268 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002269 }
2270
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002271 perf_evlist__config(evlist, &trace->opts, NULL);
2272
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002273 if (callchain_param.enabled) {
2274 bool use_identifier = false;
2275
2276 if (trace->syscalls.events.sys_exit) {
2277 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2278 &trace->opts, &callchain_param);
2279 use_identifier = true;
2280 }
2281
2282 if (pgfault_maj) {
2283 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2284 use_identifier = true;
2285 }
2286
2287 if (pgfault_min) {
2288 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2289 use_identifier = true;
2290 }
2291
2292 if (use_identifier) {
2293 /*
2294 * Now we have evsels with different sample_ids, use
2295 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2296 * from a fixed position in each ring buffer record.
2297 *
2298 * As of this the changeset introducing this comment, this
2299 * isn't strictly needed, as the fields that can come before
2300 * PERF_SAMPLE_ID are all used, but we'll probably disable
2301 * some of those for things like copying the payload of
2302 * pointer syscall arguments, and for vfs_getname we don't
2303 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2304 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2305 */
2306 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2307 perf_evlist__reset_sample_bit(evlist, ID);
2308 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002309 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002310
Namhyung Kimf15eb532012-10-05 14:02:16 +09002311 signal(SIGCHLD, sig_handler);
2312 signal(SIGINT, sig_handler);
2313
2314 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002315 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002316 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002317 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002318 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002319 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002320 }
2321 }
2322
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002323 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002324 if (err < 0)
2325 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002326
Wang Nanba504232016-02-26 09:31:54 +00002327 err = bpf__apply_obj_config();
2328 if (err) {
2329 char errbuf[BUFSIZ];
2330
2331 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2332 pr_err("ERROR: Apply config to BPF failed: %s\n",
2333 errbuf);
2334 goto out_error_open;
2335 }
2336
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002337 /*
2338 * Better not use !target__has_task() here because we need to cover the
2339 * case where no threads were specified in the command line, but a
2340 * workload was, and in that case we will fill in the thread_map when
2341 * we fork the workload in perf_evlist__prepare_workload.
2342 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002343 if (trace->filter_pids.nr > 0)
2344 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002345 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002346 err = perf_evlist__set_filter_pid(evlist, getpid());
2347
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002348 if (err < 0)
2349 goto out_error_mem;
2350
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002351 if (trace->ev_qualifier_ids.nr > 0) {
2352 err = trace__set_ev_qualifier_filter(trace);
2353 if (err < 0)
2354 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002355
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002356 pr_debug("event qualifier tracepoint filter: %s\n",
2357 trace->syscalls.events.sys_exit->filter);
2358 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002359
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002360 err = perf_evlist__apply_filters(evlist, &evsel);
2361 if (err < 0)
2362 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002363
Jiri Olsaf8850372013-11-28 17:57:22 +01002364 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002365 if (err < 0)
2366 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002367
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002368 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002369 perf_evlist__enable(evlist);
2370
Namhyung Kimf15eb532012-10-05 14:02:16 +09002371 if (forks)
2372 perf_evlist__start_workload(evlist);
2373
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002374 if (trace->opts.initial_delay) {
2375 usleep(trace->opts.initial_delay * 1000);
2376 perf_evlist__enable(evlist);
2377 }
2378
Jiri Olsae13798c2015-06-23 00:36:02 +02002379 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002380 evlist->threads->nr > 1 ||
2381 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002382again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002383 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002384
2385 for (i = 0; i < evlist->nr_mmaps; i++) {
2386 union perf_event *event;
2387
2388 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002389 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002390
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002391 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002393 err = perf_evlist__parse_sample(evlist, event, &sample);
2394 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002395 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002396 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002397 }
2398
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002399 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002400next_event:
2401 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002402
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002403 if (interrupted)
2404 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002405
2406 if (done && !draining) {
2407 perf_evlist__disable(evlist);
2408 draining = true;
2409 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002410 }
2411 }
2412
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002413 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002414 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002415
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002416 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2417 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2418 draining = true;
2419
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002420 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002421 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002422 } else {
2423 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002424 }
2425
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002426out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002427 thread__zput(trace->current);
2428
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002429 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002430
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002431 if (!err) {
2432 if (trace->summary)
2433 trace__fprintf_thread_summary(trace, trace->output);
2434
2435 if (trace->show_tool_stats) {
2436 fprintf(trace->output, "Stats:\n "
2437 " vfs_getname : %" PRIu64 "\n"
2438 " proc_getname: %" PRIu64 "\n",
2439 trace->stats.vfs_getname,
2440 trace->stats.proc_getname);
2441 }
2442 }
David Ahernbf2575c2013-10-08 21:26:53 -06002443
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002444out_delete_evlist:
2445 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002446 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002447 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002448 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002449{
2450 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002451
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002452out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002453 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002454 goto out_error;
2455
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002456out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002457 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002458 goto out_error;
2459
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002460out_error_mmap:
2461 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2462 goto out_error;
2463
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002464out_error_open:
2465 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2466
2467out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002468 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302469 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002470
2471out_error_apply_filters:
2472 fprintf(trace->output,
2473 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2474 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002475 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002476 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002478out_error_mem:
2479 fprintf(trace->output, "Not enough memory to run!\n");
2480 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002481
2482out_errno:
2483 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2484 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002485}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002486
David Ahern6810fc92013-08-28 22:29:52 -06002487static int trace__replay(struct trace *trace)
2488{
2489 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002490 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002491 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002492 struct perf_data_file file = {
2493 .path = input_name,
2494 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002495 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002496 };
David Ahern6810fc92013-08-28 22:29:52 -06002497 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002498 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002499 int err = -1;
2500
2501 trace->tool.sample = trace__process_sample;
2502 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002503 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002504 trace->tool.comm = perf_event__process_comm;
2505 trace->tool.exit = perf_event__process_exit;
2506 trace->tool.fork = perf_event__process_fork;
2507 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302508 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002509 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302510 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002511
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002512 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002513 trace->tool.ordering_requires_timestamps = true;
2514
2515 /* add tid to output */
2516 trace->multiple_threads = true;
2517
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002518 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002519 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002520 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002521
David Ahernaa07df62016-11-25 09:29:52 -07002522 if (trace->opts.target.pid)
2523 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2524
2525 if (trace->opts.target.tid)
2526 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2527
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002528 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002529 goto out;
2530
David Ahern8fb598e2013-09-28 13:13:00 -06002531 trace->host = &session->machines.host;
2532
David Ahern6810fc92013-08-28 22:29:52 -06002533 err = perf_session__set_tracepoints_handlers(session, handlers);
2534 if (err)
2535 goto out;
2536
Namhyung Kim003824e2013-11-12 15:25:00 +09002537 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2538 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002539 /* older kernels have syscalls tp versus raw_syscalls */
2540 if (evsel == NULL)
2541 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2542 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002543
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002544 if (evsel &&
2545 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2546 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002547 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2548 goto out;
2549 }
2550
2551 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2552 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002553 if (evsel == NULL)
2554 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2555 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002556 if (evsel &&
2557 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2558 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002559 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002560 goto out;
2561 }
2562
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002563 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002564 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2565 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2566 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2567 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2568 evsel->handler = trace__pgfault;
2569 }
2570
David Ahern6810fc92013-08-28 22:29:52 -06002571 setup_pager();
2572
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002573 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002574 if (err)
2575 pr_err("Failed to process events, error %d", err);
2576
David Ahernbf2575c2013-10-08 21:26:53 -06002577 else if (trace->summary)
2578 trace__fprintf_thread_summary(trace, trace->output);
2579
David Ahern6810fc92013-08-28 22:29:52 -06002580out:
2581 perf_session__delete(session);
2582
2583 return err;
2584}
2585
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002586static size_t trace__fprintf_threads_header(FILE *fp)
2587{
2588 size_t printed;
2589
Pekka Enberg99ff7152013-11-12 16:42:14 +02002590 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002591
2592 return printed;
2593}
2594
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002595DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2596 struct stats *stats;
2597 double msecs;
2598 int syscall;
2599)
2600{
2601 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2602 struct stats *stats = source->priv;
2603
2604 entry->syscall = source->i;
2605 entry->stats = stats;
2606 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2607}
2608
David Ahernbf2575c2013-10-08 21:26:53 -06002609static size_t thread__dump_stats(struct thread_trace *ttrace,
2610 struct trace *trace, FILE *fp)
2611{
David Ahernbf2575c2013-10-08 21:26:53 -06002612 size_t printed = 0;
2613 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002614 struct rb_node *nd;
2615 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002616
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002617 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002618 return 0;
2619
2620 printed += fprintf(fp, "\n");
2621
Milian Wolff834fd462015-08-06 11:24:29 +02002622 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2623 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2624 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002625
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002626 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002627 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002628 if (stats) {
2629 double min = (double)(stats->min) / NSEC_PER_MSEC;
2630 double max = (double)(stats->max) / NSEC_PER_MSEC;
2631 double avg = avg_stats(stats);
2632 double pct;
2633 u64 n = (u64) stats->n;
2634
2635 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2636 avg /= NSEC_PER_MSEC;
2637
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002638 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002639 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002640 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002641 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002642 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002643 }
David Ahernbf2575c2013-10-08 21:26:53 -06002644 }
2645
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002646 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002647 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002648
2649 return printed;
2650}
2651
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002652static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002653{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002654 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002655 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002656 double ratio;
2657
2658 if (ttrace == NULL)
2659 return 0;
2660
2661 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2662
Pekka Enberg15e65c62013-11-14 18:43:30 +02002663 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002664 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002665 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002666 if (ttrace->pfmaj)
2667 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2668 if (ttrace->pfmin)
2669 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002670 if (trace->sched)
2671 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2672 else if (fputc('\n', fp) != EOF)
2673 ++printed;
2674
David Ahernbf2575c2013-10-08 21:26:53 -06002675 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002676
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002677 return printed;
2678}
David Ahern896cbb52013-09-28 13:12:59 -06002679
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002680static unsigned long thread__nr_events(struct thread_trace *ttrace)
2681{
2682 return ttrace ? ttrace->nr_events : 0;
2683}
2684
2685DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2686 struct thread *thread;
2687)
2688{
2689 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002690}
2691
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002692static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2693{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002694 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2695 size_t printed = trace__fprintf_threads_header(fp);
2696 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002697
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002698 if (threads == NULL) {
2699 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2700 return 0;
2701 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002702
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002703 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002704 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2705
2706 resort_rb__delete(threads);
2707
2708 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002709}
2710
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002711static int trace__set_duration(const struct option *opt, const char *str,
2712 int unset __maybe_unused)
2713{
2714 struct trace *trace = opt->value;
2715
2716 trace->duration_filter = atof(str);
2717 return 0;
2718}
2719
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002720static int trace__set_filter_pids(const struct option *opt, const char *str,
2721 int unset __maybe_unused)
2722{
2723 int ret = -1;
2724 size_t i;
2725 struct trace *trace = opt->value;
2726 /*
2727 * FIXME: introduce a intarray class, plain parse csv and create a
2728 * { int nr, int entries[] } struct...
2729 */
2730 struct intlist *list = intlist__new(str);
2731
2732 if (list == NULL)
2733 return -1;
2734
2735 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2736 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2737
2738 if (trace->filter_pids.entries == NULL)
2739 goto out;
2740
2741 trace->filter_pids.entries[0] = getpid();
2742
2743 for (i = 1; i < trace->filter_pids.nr; ++i)
2744 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2745
2746 intlist__delete(list);
2747 ret = 0;
2748out:
2749 return ret;
2750}
2751
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002752static int trace__open_output(struct trace *trace, const char *filename)
2753{
2754 struct stat st;
2755
2756 if (!stat(filename, &st) && st.st_size) {
2757 char oldname[PATH_MAX];
2758
2759 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2760 unlink(oldname);
2761 rename(filename, oldname);
2762 }
2763
2764 trace->output = fopen(filename, "w");
2765
2766 return trace->output == NULL ? -errno : 0;
2767}
2768
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002769static int parse_pagefaults(const struct option *opt, const char *str,
2770 int unset __maybe_unused)
2771{
2772 int *trace_pgfaults = opt->value;
2773
2774 if (strcmp(str, "all") == 0)
2775 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2776 else if (strcmp(str, "maj") == 0)
2777 *trace_pgfaults |= TRACE_PFMAJ;
2778 else if (strcmp(str, "min") == 0)
2779 *trace_pgfaults |= TRACE_PFMIN;
2780 else
2781 return -1;
2782
2783 return 0;
2784}
2785
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002786static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2787{
2788 struct perf_evsel *evsel;
2789
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002790 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002791 evsel->handler = handler;
2792}
2793
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002794/*
2795 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2796 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2797 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2798 *
2799 * It'd be better to introduce a parse_options() variant that would return a
2800 * list with the terms it didn't match to an event...
2801 */
2802static int trace__parse_events_option(const struct option *opt, const char *str,
2803 int unset __maybe_unused)
2804{
2805 struct trace *trace = (struct trace *)opt->value;
2806 const char *s = str;
2807 char *sep = NULL, *lists[2] = { NULL, NULL, };
2808 int len = strlen(str), err = -1, list;
2809 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2810 char group_name[PATH_MAX];
2811
2812 if (strace_groups_dir == NULL)
2813 return -1;
2814
2815 if (*s == '!') {
2816 ++s;
2817 trace->not_ev_qualifier = true;
2818 }
2819
2820 while (1) {
2821 if ((sep = strchr(s, ',')) != NULL)
2822 *sep = '\0';
2823
2824 list = 0;
2825 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2826 list = 1;
2827 } else {
2828 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2829 if (access(group_name, R_OK) == 0)
2830 list = 1;
2831 }
2832
2833 if (lists[list]) {
2834 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2835 } else {
2836 lists[list] = malloc(len);
2837 if (lists[list] == NULL)
2838 goto out;
2839 strcpy(lists[list], s);
2840 }
2841
2842 if (!sep)
2843 break;
2844
2845 *sep = ',';
2846 s = sep + 1;
2847 }
2848
2849 if (lists[1] != NULL) {
2850 struct strlist_config slist_config = {
2851 .dirname = strace_groups_dir,
2852 };
2853
2854 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2855 if (trace->ev_qualifier == NULL) {
2856 fputs("Not enough memory to parse event qualifier", trace->output);
2857 goto out;
2858 }
2859
2860 if (trace__validate_ev_qualifier(trace))
2861 goto out;
2862 }
2863
2864 err = 0;
2865
2866 if (lists[0]) {
2867 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2868 "event selector. use 'perf list' to list available events",
2869 parse_events_option);
2870 err = parse_events_option(&o, lists[0], 0);
2871 }
2872out:
2873 if (sep)
2874 *sep = ',';
2875
2876 return err;
2877}
2878
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002879int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002880{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002881 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002882 "perf trace [<options>] [<command>]",
2883 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002884 "perf trace record [<options>] [<command>]",
2885 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002886 NULL
2887 };
2888 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002889 .syscalls = {
2890 . max = -1,
2891 },
2892 .opts = {
2893 .target = {
2894 .uid = UINT_MAX,
2895 .uses_mmap = true,
2896 },
2897 .user_freq = UINT_MAX,
2898 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002899 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002900 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002901 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002902 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002903 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002904 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002905 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002906 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002907 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002908 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002909 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002910 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002911 OPT_CALLBACK('e', "event", &trace, "event",
2912 "event/syscall selector. use 'perf list' to list available events",
2913 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002914 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2915 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002916 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002917 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2918 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002919 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002920 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002921 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2922 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002923 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002924 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002925 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2926 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002927 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002928 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002929 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002930 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002931 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002932 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002933 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2934 "number of mmap data pages",
2935 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002936 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002937 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002938 OPT_CALLBACK(0, "duration", &trace, "float",
2939 "show only events with duration > N.M ms",
2940 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002941 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002942 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002943 OPT_BOOLEAN('T', "time", &trace.full_time,
2944 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002945 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2946 "Show only syscall summary with statistics"),
2947 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2948 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002949 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2950 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002951 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002952 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002953 OPT_CALLBACK(0, "call-graph", &trace.opts,
2954 "record_mode[,record_size]", record_callchain_help,
2955 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002956 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2957 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002958 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2959 "Set the minimum stack depth when parsing the callchain, "
2960 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002961 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2962 "Set the maximum stack depth when parsing the callchain, "
2963 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002964 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002965 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2966 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002967 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2968 "ms to wait before starting measurement after program "
2969 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002970 OPT_END()
2971 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002972 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002973 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002974 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002975 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002976 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002977
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002978 signal(SIGSEGV, sighandler_dump_stack);
2979 signal(SIGFPE, sighandler_dump_stack);
2980
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002981 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002982 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002983
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002984 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002985 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002986 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002987 goto out;
2988 }
2989
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002990 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2991 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07002992
Wang Nand7888572016-04-08 15:07:24 +00002993 err = bpf__setup_stdout(trace.evlist);
2994 if (err) {
2995 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
2996 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
2997 goto out;
2998 }
2999
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003000 err = -1;
3001
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003002 if (trace.trace_pgfaults) {
3003 trace.opts.sample_address = true;
3004 trace.opts.sample_time = true;
3005 }
3006
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003007 if (trace.opts.mmap_pages == UINT_MAX)
3008 mmap_pages_user_set = false;
3009
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003010 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003011 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003012 max_stack_user_set = false;
3013 }
3014
3015#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003016 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003017 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3018#endif
3019
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003020 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003021 if (!mmap_pages_user_set && geteuid() == 0)
3022 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3023
Milian Wolff566a0882016-04-08 13:34:15 +02003024 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003025 }
Milian Wolff566a0882016-04-08 13:34:15 +02003026
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003027 if (trace.evlist->nr_entries > 0)
3028 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3029
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003030 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3031 return trace__record(&trace, argc-1, &argv[1]);
3032
3033 /* summary_only implies summary option, but don't overwrite summary if set */
3034 if (trace.summary_only)
3035 trace.summary = trace.summary_only;
3036
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003037 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3038 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003039 pr_err("Please specify something to trace.\n");
3040 return -1;
3041 }
3042
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003043 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003044 pr_err("The -e option can't be used with --no-syscalls.\n");
3045 goto out;
3046 }
3047
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003048 if (output_name != NULL) {
3049 err = trace__open_output(&trace, output_name);
3050 if (err < 0) {
3051 perror("failed to create output file");
3052 goto out;
3053 }
3054 }
3055
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003056 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3057
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003058 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003059 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003060 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003061 fprintf(trace.output, "%s", bf);
3062 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003063 }
3064
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003065 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003066 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003067 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003068 fprintf(trace.output, "%s", bf);
3069 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003070 }
3071
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003072 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003073 trace.opts.target.system_wide = true;
3074
David Ahern6810fc92013-08-28 22:29:52 -06003075 if (input_name)
3076 err = trace__replay(&trace);
3077 else
3078 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003079
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003080out_close:
3081 if (output_name != NULL)
3082 fclose(trace.output);
3083out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003084 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003085}