blob: 1f070bc437423dfe7e85564f6c898d0462c604ec [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030024#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030025#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060026#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030027#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030028#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060029#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030030#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060031#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030032#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060033#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030034#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060035#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030036#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010037#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070038#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000039#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020040#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030041#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030042#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030043#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030044#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030045
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030046#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030047#include <inttypes.h>
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030048#include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030049#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030050#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030052#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020053#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030054#include <linux/filter.h>
55#include <linux/audit.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030060
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030061#include "sane_ctype.h"
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef O_CLOEXEC
64# define O_CLOEXEC 02000000
65#endif
66
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030067#ifndef F_LINUX_SPECIFIC_BASE
68# define F_LINUX_SPECIFIC_BASE 1024
69#endif
70
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030071struct trace {
72 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030073 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030074 struct {
75 int max;
76 struct syscall *table;
77 struct {
78 struct perf_evsel *sys_enter,
79 *sys_exit;
80 } events;
81 } syscalls;
82 struct record_opts opts;
83 struct perf_evlist *evlist;
84 struct machine *host;
85 struct thread *current;
86 u64 base_time;
87 FILE *output;
88 unsigned long nr_events;
89 struct strlist *ev_qualifier;
90 struct {
91 size_t nr;
92 int *entries;
93 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030094 struct {
95 size_t nr;
96 pid_t *entries;
97 } filter_pids;
98 double duration_filter;
99 double runtime_ms;
100 struct {
101 u64 vfs_getname,
102 proc_getname;
103 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300104 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300105 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106 bool not_ev_qualifier;
107 bool live;
108 bool full_time;
109 bool sched;
110 bool multiple_threads;
111 bool summary;
112 bool summary_only;
113 bool show_comm;
114 bool show_tool_stats;
115 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300116 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117 bool force;
118 bool vfs_getname;
119 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300120 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300122
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300123struct tp_field {
124 int offset;
125 union {
126 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
127 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
128 };
129};
130
131#define TP_UINT_FIELD(bits) \
132static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
133{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500134 u##bits value; \
135 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
136 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300137}
138
139TP_UINT_FIELD(8);
140TP_UINT_FIELD(16);
141TP_UINT_FIELD(32);
142TP_UINT_FIELD(64);
143
144#define TP_UINT_FIELD__SWAPPED(bits) \
145static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
146{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500147 u##bits value; \
148 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300149 return bswap_##bits(value);\
150}
151
152TP_UINT_FIELD__SWAPPED(16);
153TP_UINT_FIELD__SWAPPED(32);
154TP_UINT_FIELD__SWAPPED(64);
155
156static int tp_field__init_uint(struct tp_field *field,
157 struct format_field *format_field,
158 bool needs_swap)
159{
160 field->offset = format_field->offset;
161
162 switch (format_field->size) {
163 case 1:
164 field->integer = tp_field__u8;
165 break;
166 case 2:
167 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
168 break;
169 case 4:
170 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
171 break;
172 case 8:
173 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
174 break;
175 default:
176 return -1;
177 }
178
179 return 0;
180}
181
182static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
183{
184 return sample->raw_data + field->offset;
185}
186
187static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
188{
189 field->offset = format_field->offset;
190 field->pointer = tp_field__ptr;
191 return 0;
192}
193
194struct syscall_tp {
195 struct tp_field id;
196 union {
197 struct tp_field args, ret;
198 };
199};
200
201static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
202 struct tp_field *field,
203 const char *name)
204{
205 struct format_field *format_field = perf_evsel__field(evsel, name);
206
207 if (format_field == NULL)
208 return -1;
209
210 return tp_field__init_uint(field, format_field, evsel->needs_swap);
211}
212
213#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
214 ({ struct syscall_tp *sc = evsel->priv;\
215 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
216
217static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
218 struct tp_field *field,
219 const char *name)
220{
221 struct format_field *format_field = perf_evsel__field(evsel, name);
222
223 if (format_field == NULL)
224 return -1;
225
226 return tp_field__init_ptr(field, format_field);
227}
228
229#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
230 ({ struct syscall_tp *sc = evsel->priv;\
231 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
232
233static void perf_evsel__delete_priv(struct perf_evsel *evsel)
234{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300235 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300236 perf_evsel__delete(evsel);
237}
238
Namhyung Kim96695d42013-11-12 08:51:45 -0300239static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
240{
241 evsel->priv = malloc(sizeof(struct syscall_tp));
242 if (evsel->priv != NULL) {
243 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
244 goto out_delete;
245
246 evsel->handler = handler;
247 return 0;
248 }
249
250 return -ENOMEM;
251
252out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300253 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300254 return -ENOENT;
255}
256
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300257static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300258{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300259 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300260
David Ahern9aca7f12013-12-04 19:41:39 -0700261 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200262 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700263 evsel = perf_evsel__newtp("syscalls", direction);
264
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200265 if (IS_ERR(evsel))
266 return NULL;
267
268 if (perf_evsel__init_syscall_tp(evsel, handler))
269 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300270
271 return evsel;
272
273out_delete:
274 perf_evsel__delete_priv(evsel);
275 return NULL;
276}
277
278#define perf_evsel__sc_tp_uint(evsel, name, sample) \
279 ({ struct syscall_tp *fields = evsel->priv; \
280 fields->name.integer(&fields->name, sample); })
281
282#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
283 ({ struct syscall_tp *fields = evsel->priv; \
284 fields->name.pointer(&fields->name, sample); })
285
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300286struct strarray {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300287 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300288 int nr_entries;
289 const char **entries;
290};
291
292#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
293 .nr_entries = ARRAY_SIZE(array), \
294 .entries = array, \
295}
296
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300297#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
298 .offset = off, \
299 .nr_entries = ARRAY_SIZE(array), \
300 .entries = array, \
301}
302
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300303static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
304 const char *intfmt,
305 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300306{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300307 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300308 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300309
310 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300311 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300312
313 return scnprintf(bf, size, "%s", sa->entries[idx]);
314}
315
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300316static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
317 struct syscall_arg *arg)
318{
319 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
320}
321
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300322#define SCA_STRARRAY syscall_arg__scnprintf_strarray
323
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300324struct strarrays {
325 int nr_entries;
326 struct strarray **entries;
327};
328
329#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
330 .nr_entries = ARRAY_SIZE(array), \
331 .entries = array, \
332}
333
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300334size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
335 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300336{
337 struct strarrays *sas = arg->parm;
338 int i;
339
340 for (i = 0; i < sas->nr_entries; ++i) {
341 struct strarray *sa = sas->entries[i];
342 int idx = arg->val - sa->offset;
343
344 if (idx >= 0 && idx < sa->nr_entries) {
345 if (sa->entries[idx] == NULL)
346 break;
347 return scnprintf(bf, size, "%s", sa->entries[idx]);
348 }
349 }
350
351 return scnprintf(bf, size, "%d", arg->val);
352}
353
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300354#if defined(__i386__) || defined(__x86_64__)
355/*
356 * FIXME: Make this available to all arches as soon as the ioctl beautifier
357 * gets rewritten to support all arches.
358 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300359static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
360 struct syscall_arg *arg)
361{
362 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
363}
364
365#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300366#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300367
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300368static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
369 struct syscall_arg *arg);
370
371#define SCA_FD syscall_arg__scnprintf_fd
372
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300373#ifndef AT_FDCWD
374#define AT_FDCWD -100
375#endif
376
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300377static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
378 struct syscall_arg *arg)
379{
380 int fd = arg->val;
381
382 if (fd == AT_FDCWD)
383 return scnprintf(bf, size, "CWD");
384
385 return syscall_arg__scnprintf_fd(bf, size, arg);
386}
387
388#define SCA_FDAT syscall_arg__scnprintf_fd_at
389
390static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
391 struct syscall_arg *arg);
392
393#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
394
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300395size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300396{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300397 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300398}
399
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300400size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300401{
402 return scnprintf(bf, size, "%d", arg->val);
403}
404
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300405size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
406{
407 return scnprintf(bf, size, "%ld", arg->val);
408}
409
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300410static const char *bpf_cmd[] = {
411 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
412 "MAP_GET_NEXT_KEY", "PROG_LOAD",
413};
414static DEFINE_STRARRAY(bpf_cmd);
415
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300416static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
417static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300418
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300419static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
420static DEFINE_STRARRAY(itimers);
421
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300422static const char *keyctl_options[] = {
423 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
424 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
425 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
426 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
427 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
428};
429static DEFINE_STRARRAY(keyctl_options);
430
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300431static const char *whences[] = { "SET", "CUR", "END",
432#ifdef SEEK_DATA
433"DATA",
434#endif
435#ifdef SEEK_HOLE
436"HOLE",
437#endif
438};
439static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300440
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300441static const char *fcntl_cmds[] = {
442 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300443 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
444 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
445 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300446};
447static DEFINE_STRARRAY(fcntl_cmds);
448
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300449static const char *fcntl_linux_specific_cmds[] = {
450 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
451 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300452 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300453};
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 Melo9c47f662017-07-14 11:05:40 -0300664 .arg_scnprintf = { [1] = SCA_FCNTL_CMD, /* cmd */
665 [2] = SCA_FCNTL_ARG, /* arg */ },
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300666 .arg_parm = { [1] = &strarrays__fcntl_cmds_arrays, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300667 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300668 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300669 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
670 { .name = "fsetxattr", .errmsg = true, },
671 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300672 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300673 { .name = "fstatfs", .errmsg = true, },
674 { .name = "fsync", .errmsg = true, },
675 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300676 { .name = "futex", .errmsg = true,
677 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300678 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300679 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300680 { .name = "getdents", .errmsg = true, },
681 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300682 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300683 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300684 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300685 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300686 { .name = "getrandom", .errmsg = true,
687 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300688 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300689 { .name = "getxattr", .errmsg = true, },
690 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300691 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300692 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300693#if defined(__i386__) || defined(__x86_64__)
694/*
695 * FIXME: Make this available to all arches.
696 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300697 [1] = SCA_STRHEXARRAY, /* cmd */
698 [2] = SCA_HEX, /* arg */ },
699 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300700#else
701 [2] = SCA_HEX, /* arg */ }, },
702#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300703 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300704 { .name = "kill", .errmsg = true,
705 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300706 { .name = "lchown", .errmsg = true, },
707 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300708 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300709 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300710 { .name = "listxattr", .errmsg = true, },
711 { .name = "llistxattr", .errmsg = true, },
712 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300713 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300714 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300715 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300716 { .name = "lsetxattr", .errmsg = true, },
717 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
718 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300719 { .name = "madvise", .errmsg = true,
720 .arg_scnprintf = { [0] = SCA_HEX, /* start */
721 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300722 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300723 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300724 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
725 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300726 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300727 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300728 { .name = "mlock", .errmsg = true,
729 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
730 { .name = "mlockall", .errmsg = true,
731 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300732 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200733/* The standard mmap maps to old_mmap on s390x */
734#if defined(__s390x__)
735 .alias = "old_mmap",
736#endif
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300737 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300738 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300739 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300740 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300741 .arg_scnprintf = { [0] = SCA_HEX, /* start */
742 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300743 { .name = "mq_unlink", .errmsg = true,
744 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300745 { .name = "mremap", .hexret = true,
746 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300747 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300748 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300749 { .name = "munlock", .errmsg = true,
750 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300751 { .name = "munmap", .errmsg = true,
752 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300753 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300754 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300755 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300756 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300757 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300758 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300759 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300760 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
761 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300762 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300763 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
764 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300765 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300766 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300767 [3] = SCA_FD, /* group_fd */
768 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300769 { .name = "pipe2", .errmsg = true,
770 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300771 { .name = "poll", .errmsg = true, .timeout = true, },
772 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300773 { .name = "pread", .errmsg = true, .alias = "pread64", },
774 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300775 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300776 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
777 { .name = "pwritev", .errmsg = true, },
778 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300779 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300780 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300781 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300782 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300783 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300784 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300785 { .name = "recvmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300786 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300787 { .name = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300788 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300789 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300790 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300791 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300792 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300793 { .name = "rt_sigaction", .errmsg = true,
794 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300795 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300796 { .name = "rt_sigqueueinfo", .errmsg = true,
797 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
798 { .name = "rt_tgsigqueueinfo", .errmsg = true,
799 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300800 { .name = "sched_getattr", .errmsg = true, },
801 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300802 { .name = "sched_setscheduler", .errmsg = true,
803 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300804 { .name = "seccomp", .errmsg = true,
805 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
806 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300807 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300808 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300809 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300810 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300811 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300812 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300813 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300814 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300815 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300816 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300817 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300818 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300819 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300820 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300821 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
822 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300823 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300824 { .name = "socketpair", .errmsg = true,
825 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
826 [1] = SCA_SK_TYPE, /* type */ },
827 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300828 { .name = "stat", .errmsg = true, .alias = "newstat", },
829 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300830 { .name = "statx", .errmsg = true,
831 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
832 [2] = SCA_STATX_FLAGS, /* flags */
833 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300834 { .name = "swapoff", .errmsg = true,
835 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
836 { .name = "swapon", .errmsg = true,
837 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300838 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300839 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300840 { .name = "tgkill", .errmsg = true,
841 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
842 { .name = "tkill", .errmsg = true,
843 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300844 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300845 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300846 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300847 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
848 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300849 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300850 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
851 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300852 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300853 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300854 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300855 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300856 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300857 { .name = "write", .errmsg = true, },
858 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300859};
860
861static int syscall_fmt__cmp(const void *name, const void *fmtp)
862{
863 const struct syscall_fmt *fmt = fmtp;
864 return strcmp(name, fmt->name);
865}
866
867static struct syscall_fmt *syscall_fmt__find(const char *name)
868{
869 const int nmemb = ARRAY_SIZE(syscall_fmts);
870 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
871}
872
873struct syscall {
874 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300875 int nr_args;
876 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300877 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300878 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300879 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300880 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300881 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300882};
883
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300884/*
885 * We need to have this 'calculated' boolean because in some cases we really
886 * don't know what is the duration of a syscall, for instance, when we start
887 * a session and some threads are waiting for a syscall to finish, say 'poll',
888 * in which case all we can do is to print "( ? ) for duration and for the
889 * start timestamp.
890 */
891static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200892{
893 double duration = (double)t / NSEC_PER_MSEC;
894 size_t printed = fprintf(fp, "(");
895
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300896 if (!calculated)
897 printed += fprintf(fp, " ? ");
898 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200899 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
900 else if (duration >= 0.01)
901 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
902 else
903 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300904 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200905}
906
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300907/**
908 * filename.ptr: The filename char pointer that will be vfs_getname'd
909 * filename.entry_str_pos: Where to insert the string translated from
910 * filename.ptr by the vfs_getname tracepoint/kprobe.
911 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912struct thread_trace {
913 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300914 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300915 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400916 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300917 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300918 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300919 struct {
920 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300921 short int entry_str_pos;
922 bool pending_open;
923 unsigned int namelen;
924 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300925 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926 struct {
927 int max;
928 char **table;
929 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600930
931 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300932};
933
934static struct thread_trace *thread_trace__new(void)
935{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300936 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
937
938 if (ttrace)
939 ttrace->paths.max = -1;
940
David Ahernbf2575c2013-10-08 21:26:53 -0600941 ttrace->syscall_stats = intlist__new(NULL);
942
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300943 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300944}
945
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300946static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300947{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300948 struct thread_trace *ttrace;
949
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300950 if (thread == NULL)
951 goto fail;
952
Namhyung Kim89dceb22014-10-06 09:46:03 +0900953 if (thread__priv(thread) == NULL)
954 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300955
Namhyung Kim89dceb22014-10-06 09:46:03 +0900956 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300957 goto fail;
958
Namhyung Kim89dceb22014-10-06 09:46:03 +0900959 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300960 ++ttrace->nr_events;
961
962 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300963fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300964 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300965 "WARNING: not enough memory, dropping samples!\n");
966 return NULL;
967}
968
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400969#define TRACE_PFMAJ (1 << 0)
970#define TRACE_PFMIN (1 << 1)
971
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300972static const size_t trace__entry_str_size = 2048;
973
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300974static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900976 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300977
978 if (fd > ttrace->paths.max) {
979 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
980
981 if (npath == NULL)
982 return -1;
983
984 if (ttrace->paths.max != -1) {
985 memset(npath + ttrace->paths.max + 1, 0,
986 (fd - ttrace->paths.max) * sizeof(char *));
987 } else {
988 memset(npath, 0, (fd + 1) * sizeof(char *));
989 }
990
991 ttrace->paths.table = npath;
992 ttrace->paths.max = fd;
993 }
994
995 ttrace->paths.table[fd] = strdup(pathname);
996
997 return ttrace->paths.table[fd] != NULL ? 0 : -1;
998}
999
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001000static int thread__read_fd_path(struct thread *thread, int fd)
1001{
1002 char linkname[PATH_MAX], pathname[PATH_MAX];
1003 struct stat st;
1004 int ret;
1005
1006 if (thread->pid_ == thread->tid) {
1007 scnprintf(linkname, sizeof(linkname),
1008 "/proc/%d/fd/%d", thread->pid_, fd);
1009 } else {
1010 scnprintf(linkname, sizeof(linkname),
1011 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1012 }
1013
1014 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1015 return -1;
1016
1017 ret = readlink(linkname, pathname, sizeof(pathname));
1018
1019 if (ret < 0 || ret > st.st_size)
1020 return -1;
1021
1022 pathname[ret] = '\0';
1023 return trace__set_fd_pathname(thread, fd, pathname);
1024}
1025
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001026static const char *thread__fd_path(struct thread *thread, int fd,
1027 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001028{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001029 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001030
1031 if (ttrace == NULL)
1032 return NULL;
1033
1034 if (fd < 0)
1035 return NULL;
1036
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001037 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001038 if (!trace->live)
1039 return NULL;
1040 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001041 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001042 return NULL;
1043 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001044
1045 return ttrace->paths.table[fd];
1046}
1047
1048static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1049 struct syscall_arg *arg)
1050{
1051 int fd = arg->val;
1052 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001053 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054
1055 if (path)
1056 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1057
1058 return printed;
1059}
1060
1061static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1062 struct syscall_arg *arg)
1063{
1064 int fd = arg->val;
1065 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001066 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001067
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001068 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1069 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001070
1071 return printed;
1072}
1073
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001074static void thread__set_filename_pos(struct thread *thread, const char *bf,
1075 unsigned long ptr)
1076{
1077 struct thread_trace *ttrace = thread__priv(thread);
1078
1079 ttrace->filename.ptr = ptr;
1080 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1081}
1082
1083static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1084 struct syscall_arg *arg)
1085{
1086 unsigned long ptr = arg->val;
1087
1088 if (!arg->trace->vfs_getname)
1089 return scnprintf(bf, size, "%#x", ptr);
1090
1091 thread__set_filename_pos(arg->thread, bf, ptr);
1092 return 0;
1093}
1094
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001095static bool trace__filter_duration(struct trace *trace, double t)
1096{
1097 return t < (trace->duration_filter * NSEC_PER_MSEC);
1098}
1099
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001100static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101{
1102 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1103
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001104 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001105}
1106
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001107/*
1108 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1109 * using ttrace->entry_time for a thread that receives a sys_exit without
1110 * first having received a sys_enter ("poll" issued before tracing session
1111 * starts, lost sys_enter exit due to ring buffer overflow).
1112 */
1113static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1114{
1115 if (tstamp > 0)
1116 return __trace__fprintf_tstamp(trace, tstamp, fp);
1117
1118 return fprintf(fp, " ? ");
1119}
1120
Namhyung Kimf15eb532012-10-05 14:02:16 +09001121static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001122static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001123
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001124static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001125{
1126 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001127 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001128}
1129
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001130static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001131 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001132{
1133 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001134 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001135
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001136 if (trace->multiple_threads) {
1137 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001138 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001139 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001140 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001141
1142 return printed;
1143}
1144
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001145static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001146 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001147{
1148 int ret = 0;
1149
1150 switch (event->header.type) {
1151 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001152 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001153 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001154 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001155 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001156 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001157 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001158 break;
1159 }
1160
1161 return ret;
1162}
1163
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001164static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001165 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001166 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001167 struct machine *machine)
1168{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001169 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001170 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001171}
1172
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001173static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1174{
1175 struct machine *machine = vmachine;
1176
1177 if (machine->kptr_restrict_warned)
1178 return NULL;
1179
1180 if (symbol_conf.kptr_restrict) {
1181 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1182 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1183 "Kernel samples will not be resolved.\n");
1184 machine->kptr_restrict_warned = true;
1185 return NULL;
1186 }
1187
1188 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1189}
1190
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001191static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1192{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001193 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001194
1195 if (err)
1196 return err;
1197
David Ahern8fb598e2013-09-28 13:13:00 -06001198 trace->host = machine__new_host();
1199 if (trace->host == NULL)
1200 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001201
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001202 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001203 return -errno;
1204
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001205 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001206 evlist->threads, trace__tool_process, false,
1207 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001208 if (err)
1209 symbol__exit();
1210
1211 return err;
1212}
1213
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001214static int syscall__set_arg_fmts(struct syscall *sc)
1215{
1216 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001217 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001218
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001219 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001220 if (sc->arg_scnprintf == NULL)
1221 return -1;
1222
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001223 if (sc->fmt)
1224 sc->arg_parm = sc->fmt->arg_parm;
1225
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001226 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001227 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1228 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001229 else if (strcmp(field->type, "const char *") == 0 &&
1230 (strcmp(field->name, "filename") == 0 ||
1231 strcmp(field->name, "path") == 0 ||
1232 strcmp(field->name, "pathname") == 0))
1233 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001234 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001235 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001236 else if (strcmp(field->type, "pid_t") == 0)
1237 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001238 else if (strcmp(field->type, "umode_t") == 0)
1239 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001240 else if ((strcmp(field->type, "int") == 0 ||
1241 strcmp(field->type, "unsigned int") == 0 ||
1242 strcmp(field->type, "long") == 0) &&
1243 (len = strlen(field->name)) >= 2 &&
1244 strcmp(field->name + len - 2, "fd") == 0) {
1245 /*
1246 * /sys/kernel/tracing/events/syscalls/sys_enter*
1247 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1248 * 65 int
1249 * 23 unsigned int
1250 * 7 unsigned long
1251 */
1252 sc->arg_scnprintf[idx] = SCA_FD;
1253 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001254 ++idx;
1255 }
1256
1257 return 0;
1258}
1259
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001260static int trace__read_syscall_info(struct trace *trace, int id)
1261{
1262 char tp_name[128];
1263 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001264 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001265
1266 if (name == NULL)
1267 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001268
1269 if (id > trace->syscalls.max) {
1270 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1271
1272 if (nsyscalls == NULL)
1273 return -1;
1274
1275 if (trace->syscalls.max != -1) {
1276 memset(nsyscalls + trace->syscalls.max + 1, 0,
1277 (id - trace->syscalls.max) * sizeof(*sc));
1278 } else {
1279 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1280 }
1281
1282 trace->syscalls.table = nsyscalls;
1283 trace->syscalls.max = id;
1284 }
1285
1286 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001287 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001288
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001289 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001290
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001291 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001292 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001293
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001294 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001295 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001296 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001297 }
1298
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001299 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001300 return -1;
1301
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001302 sc->args = sc->tp_format->format.fields;
1303 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001304 /*
1305 * We need to check and discard the first variable '__syscall_nr'
1306 * or 'nr' that mean the syscall number. It is needless here.
1307 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1308 */
1309 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001310 sc->args = sc->args->next;
1311 --sc->nr_args;
1312 }
1313
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001314 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1315
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001316 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001317}
1318
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001319static int trace__validate_ev_qualifier(struct trace *trace)
1320{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001321 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001322 struct str_node *pos;
1323
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001324 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1325 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1326 sizeof(trace->ev_qualifier_ids.entries[0]));
1327
1328 if (trace->ev_qualifier_ids.entries == NULL) {
1329 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1330 trace->output);
1331 err = -EINVAL;
1332 goto out;
1333 }
1334
1335 i = 0;
1336
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001337 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001338 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001339 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001340
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001341 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001342 if (err == 0) {
1343 fputs("Error:\tInvalid syscall ", trace->output);
1344 err = -EINVAL;
1345 } else {
1346 fputs(", ", trace->output);
1347 }
1348
1349 fputs(sc, trace->output);
1350 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001351
1352 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001353 }
1354
1355 if (err < 0) {
1356 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1357 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001358 zfree(&trace->ev_qualifier_ids.entries);
1359 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001360 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001361out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001362 return err;
1363}
1364
David Ahern55d43bca2015-02-19 15:00:22 -05001365/*
1366 * args is to be interpreted as a series of longs but we need to handle
1367 * 8-byte unaligned accesses. args points to raw_data within the event
1368 * and raw_data is guaranteed to be 8-byte unaligned because it is
1369 * preceded by raw_size which is a u32. So we need to copy args to a temp
1370 * variable to read it. Most notably this avoids extended load instructions
1371 * on unaligned addresses
1372 */
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001373static unsigned long __syscall_arg__val(unsigned char *args, u8 idx)
1374{
1375 unsigned long val;
1376 unsigned char *p = args + sizeof(unsigned long) * idx;
1377
1378 memcpy(&val, p, sizeof(val));
1379 return val;
1380}
1381
1382unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
1383{
1384 return __syscall_arg__val(arg->args, idx);
1385}
David Ahern55d43bca2015-02-19 15:00:22 -05001386
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001387static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001388 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001389 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001390{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001392 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001393
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001394 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001395 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001396 u8 bit = 1;
1397 struct syscall_arg arg = {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001398 .args = args,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001399 .idx = 0,
1400 .mask = 0,
1401 .trace = trace,
1402 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001403 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001404
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001405 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001406 field = field->next, ++arg.idx, bit <<= 1) {
1407 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001408 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001409
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001410 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001411
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001412 /*
1413 * Suppress this argument if its value is zero and
1414 * and we don't have a string associated in an
1415 * strarray for it.
1416 */
David Ahern55d43bca2015-02-19 15:00:22 -05001417 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001418 !(sc->arg_scnprintf &&
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -03001419 (sc->arg_scnprintf[arg.idx] == SCA_STRARRAY ||
1420 sc->arg_scnprintf[arg.idx] == SCA_STRARRAYS) &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001421 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001422 continue;
1423
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001424 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001425 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001426 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001427 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001428 if (sc->arg_parm)
1429 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001430 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1431 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001432 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001433 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001434 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001435 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001436 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001437 } else if (IS_ERR(sc->tp_format)) {
1438 /*
1439 * If we managed to read the tracepoint /format file, then we
1440 * may end up not having any args, like with gettid(), so only
1441 * print the raw args when we didn't manage to read it.
1442 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001443 int i = 0;
1444
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001445 while (i < 6) {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001446 val = __syscall_arg__val(args, i);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001447 printed += scnprintf(bf + printed, size - printed,
1448 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001449 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001450 ++i;
1451 }
1452 }
1453
1454 return printed;
1455}
1456
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001457typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001458 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001459 struct perf_sample *sample);
1460
1461static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001462 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001463{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001464
1465 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001466
1467 /*
1468 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1469 * before that, leaving at a higher verbosity level till that is
1470 * explained. Reproduced with plain ftrace with:
1471 *
1472 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1473 * grep "NR -1 " /t/trace_pipe
1474 *
1475 * After generating some load on the machine.
1476 */
1477 if (verbose > 1) {
1478 static u64 n;
1479 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1480 id, perf_evsel__name(evsel), ++n);
1481 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001482 return NULL;
1483 }
1484
1485 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1486 trace__read_syscall_info(trace, id))
1487 goto out_cant_read;
1488
1489 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1490 goto out_cant_read;
1491
1492 return &trace->syscalls.table[id];
1493
1494out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001495 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001496 fprintf(trace->output, "Problems reading syscall %d", id);
1497 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1498 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1499 fputs(" information\n", trace->output);
1500 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001501 return NULL;
1502}
1503
David Ahernbf2575c2013-10-08 21:26:53 -06001504static void thread__update_stats(struct thread_trace *ttrace,
1505 int id, struct perf_sample *sample)
1506{
1507 struct int_node *inode;
1508 struct stats *stats;
1509 u64 duration = 0;
1510
1511 inode = intlist__findnew(ttrace->syscall_stats, id);
1512 if (inode == NULL)
1513 return;
1514
1515 stats = inode->priv;
1516 if (stats == NULL) {
1517 stats = malloc(sizeof(struct stats));
1518 if (stats == NULL)
1519 return;
1520 init_stats(stats);
1521 inode->priv = stats;
1522 }
1523
1524 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1525 duration = sample->time - ttrace->entry_time;
1526
1527 update_stats(stats, duration);
1528}
1529
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001530static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1531{
1532 struct thread_trace *ttrace;
1533 u64 duration;
1534 size_t printed;
1535
1536 if (trace->current == NULL)
1537 return 0;
1538
1539 ttrace = thread__priv(trace->current);
1540
1541 if (!ttrace->entry_pending)
1542 return 0;
1543
1544 duration = sample->time - ttrace->entry_time;
1545
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001546 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001547 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1548 ttrace->entry_pending = false;
1549
1550 return printed;
1551}
1552
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001553static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001554 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001555 struct perf_sample *sample)
1556{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001557 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001558 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001559 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001560 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001561 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001562 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001563 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001564
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001565 if (sc == NULL)
1566 return -1;
1567
David Ahern8fb598e2013-09-28 13:13:00 -06001568 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001569 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001570 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001571 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001572
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001573 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001574
1575 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001576 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001577 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001578 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001579 }
1580
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001581 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001582 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001583
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001584 ttrace->entry_time = sample->time;
1585 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001586 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001587
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001588 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001589 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001590
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001591 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001592 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001593 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001594 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001595 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001596 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001597 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001598 /* See trace__vfs_getname & trace__sys_exit */
1599 ttrace->filename.pending_open = false;
1600 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001601
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001602 if (trace->current != thread) {
1603 thread__put(trace->current);
1604 trace->current = thread__get(thread);
1605 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001606 err = 0;
1607out_put:
1608 thread__put(thread);
1609 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001610}
1611
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001612static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1613 struct perf_sample *sample,
1614 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001615{
1616 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001617
1618 if (machine__resolve(trace->host, &al, sample) < 0 ||
1619 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1620 return -1;
1621
1622 return 0;
1623}
1624
1625static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1626{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001627 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001628 const unsigned int print_opts = EVSEL__PRINT_SYM |
1629 EVSEL__PRINT_DSO |
1630 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001631
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001632 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001633}
1634
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001635static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001636 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001637 struct perf_sample *sample)
1638{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001639 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001640 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001641 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001642 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001643 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001644 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001645 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001646
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001647 if (sc == NULL)
1648 return -1;
1649
David Ahern8fb598e2013-09-28 13:13:00 -06001650 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001651 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001652 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001653 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001654
David Ahernbf2575c2013-10-08 21:26:53 -06001655 if (trace->summary)
1656 thread__update_stats(ttrace, id, sample);
1657
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001658 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001659
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001660 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001661 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1662 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001663 ++trace->stats.vfs_getname;
1664 }
1665
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001666 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001667 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001668 if (trace__filter_duration(trace, duration))
1669 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001670 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001671 } else if (trace->duration_filter)
1672 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001673
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001674 if (sample->callchain) {
1675 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1676 if (callchain_ret == 0) {
1677 if (callchain_cursor.nr < trace->min_stack)
1678 goto out;
1679 callchain_ret = 1;
1680 }
1681 }
1682
David Ahernfd2eaba2013-11-12 09:31:15 -07001683 if (trace->summary_only)
1684 goto out;
1685
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001686 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001687
1688 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001689 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001690 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001691 fprintf(trace->output, " ... [");
1692 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1693 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001694 }
1695
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001696 if (sc->fmt == NULL) {
1697signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001698 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001699 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001700 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001701 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001702 *e = audit_errno_to_name(-ret);
1703
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001704 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001705 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001706 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001707 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001708 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001709 else if (sc->fmt->errpid) {
1710 struct thread *child = machine__find_thread(trace->host, ret, ret);
1711
1712 if (child != NULL) {
1713 fprintf(trace->output, ") = %ld", ret);
1714 if (child->comm_set)
1715 fprintf(trace->output, " (%s)", thread__comm_str(child));
1716 thread__put(child);
1717 }
1718 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001719 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001720
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001721 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001722
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001723 if (callchain_ret > 0)
1724 trace__fprintf_callchain(trace, sample);
1725 else if (callchain_ret < 0)
1726 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001727out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001728 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001729 err = 0;
1730out_put:
1731 thread__put(thread);
1732 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001733}
1734
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001735static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001736 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001737 struct perf_sample *sample)
1738{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001739 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1740 struct thread_trace *ttrace;
1741 size_t filename_len, entry_str_len, to_move;
1742 ssize_t remaining_space;
1743 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001744 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001745
1746 if (!thread)
1747 goto out;
1748
1749 ttrace = thread__priv(thread);
1750 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001751 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001752
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001753 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001754 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001755 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001756
1757 if (ttrace->filename.namelen < filename_len) {
1758 char *f = realloc(ttrace->filename.name, filename_len + 1);
1759
1760 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001761 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001762
1763 ttrace->filename.namelen = filename_len;
1764 ttrace->filename.name = f;
1765 }
1766
1767 strcpy(ttrace->filename.name, filename);
1768 ttrace->filename.pending_open = true;
1769
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001770 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001771 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001772
1773 entry_str_len = strlen(ttrace->entry_str);
1774 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1775 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001776 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001777
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001778 if (filename_len > (size_t)remaining_space) {
1779 filename += filename_len - remaining_space;
1780 filename_len = remaining_space;
1781 }
1782
1783 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1784 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1785 memmove(pos + filename_len, pos, to_move);
1786 memcpy(pos, filename, filename_len);
1787
1788 ttrace->filename.ptr = 0;
1789 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001790out_put:
1791 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001792out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001793 return 0;
1794}
1795
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001796static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001797 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001798 struct perf_sample *sample)
1799{
1800 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1801 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001802 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001803 sample->pid,
1804 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001805 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001806
1807 if (ttrace == NULL)
1808 goto out_dump;
1809
1810 ttrace->runtime_ms += runtime_ms;
1811 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001812out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001813 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001814 return 0;
1815
1816out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001817 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001818 evsel->name,
1819 perf_evsel__strval(evsel, sample, "comm"),
1820 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1821 runtime,
1822 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001823 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001824}
1825
Wang Nan1d6c9402016-02-26 09:31:55 +00001826static void bpf_output__printer(enum binary_printer_ops op,
1827 unsigned int val, void *extra)
1828{
1829 FILE *output = extra;
1830 unsigned char ch = (unsigned char)val;
1831
1832 switch (op) {
1833 case BINARY_PRINT_CHAR_DATA:
1834 fprintf(output, "%c", isprint(ch) ? ch : '.');
1835 break;
1836 case BINARY_PRINT_DATA_BEGIN:
1837 case BINARY_PRINT_LINE_BEGIN:
1838 case BINARY_PRINT_ADDR:
1839 case BINARY_PRINT_NUM_DATA:
1840 case BINARY_PRINT_NUM_PAD:
1841 case BINARY_PRINT_SEP:
1842 case BINARY_PRINT_CHAR_PAD:
1843 case BINARY_PRINT_LINE_END:
1844 case BINARY_PRINT_DATA_END:
1845 default:
1846 break;
1847 }
1848}
1849
1850static void bpf_output__fprintf(struct trace *trace,
1851 struct perf_sample *sample)
1852{
1853 print_binary(sample->raw_data, sample->raw_size, 8,
1854 bpf_output__printer, trace->output);
1855}
1856
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001857static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1858 union perf_event *event __maybe_unused,
1859 struct perf_sample *sample)
1860{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001861 int callchain_ret = 0;
1862
1863 if (sample->callchain) {
1864 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1865 if (callchain_ret == 0) {
1866 if (callchain_cursor.nr < trace->min_stack)
1867 goto out;
1868 callchain_ret = 1;
1869 }
1870 }
1871
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001872 trace__printf_interrupted_entry(trace, sample);
1873 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001874
1875 if (trace->trace_syscalls)
1876 fprintf(trace->output, "( ): ");
1877
1878 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001879
Wang Nan1d6c9402016-02-26 09:31:55 +00001880 if (perf_evsel__is_bpf_output(evsel)) {
1881 bpf_output__fprintf(trace, sample);
1882 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001883 event_format__fprintf(evsel->tp_format, sample->cpu,
1884 sample->raw_data, sample->raw_size,
1885 trace->output);
1886 }
1887
1888 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001889
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001890 if (callchain_ret > 0)
1891 trace__fprintf_callchain(trace, sample);
1892 else if (callchain_ret < 0)
1893 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1894out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001895 return 0;
1896}
1897
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001898static void print_location(FILE *f, struct perf_sample *sample,
1899 struct addr_location *al,
1900 bool print_dso, bool print_sym)
1901{
1902
Namhyung Kimbb963e12017-02-17 17:17:38 +09001903 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001904 fprintf(f, "%s@", al->map->dso->long_name);
1905
Namhyung Kimbb963e12017-02-17 17:17:38 +09001906 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001907 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001908 al->addr - al->sym->start);
1909 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001910 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001911 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001912 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001913}
1914
1915static int trace__pgfault(struct trace *trace,
1916 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001917 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001918 struct perf_sample *sample)
1919{
1920 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001921 struct addr_location al;
1922 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001923 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001924 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001925 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001926
1927 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001928
1929 if (sample->callchain) {
1930 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1931 if (callchain_ret == 0) {
1932 if (callchain_cursor.nr < trace->min_stack)
1933 goto out_put;
1934 callchain_ret = 1;
1935 }
1936 }
1937
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001938 ttrace = thread__trace(thread, trace->output);
1939 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001940 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001941
1942 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1943 ttrace->pfmaj++;
1944 else
1945 ttrace->pfmin++;
1946
1947 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001948 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001949
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001950 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001951 sample->ip, &al);
1952
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001953 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001954
1955 fprintf(trace->output, "%sfault [",
1956 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1957 "maj" : "min");
1958
1959 print_location(trace->output, sample, &al, false, true);
1960
1961 fprintf(trace->output, "] => ");
1962
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001963 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001964 sample->addr, &al);
1965
1966 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001967 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001968 MAP__FUNCTION, sample->addr, &al);
1969
1970 if (al.map)
1971 map_type = 'x';
1972 else
1973 map_type = '?';
1974 }
1975
1976 print_location(trace->output, sample, &al, true, false);
1977
1978 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001979
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001980 if (callchain_ret > 0)
1981 trace__fprintf_callchain(trace, sample);
1982 else if (callchain_ret < 0)
1983 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001984out:
1985 err = 0;
1986out_put:
1987 thread__put(thread);
1988 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001989}
1990
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001991static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001992 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001993 struct perf_sample *sample)
1994{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001995 /*
1996 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1997 * and don't use sample->time unconditionally, we may end up having
1998 * some other event in the future without PERF_SAMPLE_TIME for good
1999 * reason, i.e. we may not be interested in its timestamps, just in
2000 * it taking place, picking some piece of information when it
2001 * appears in our event stream (vfs_getname comes to mind).
2002 */
2003 if (trace->base_time == 0 && !trace->full_time &&
2004 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002005 trace->base_time = sample->time;
2006}
2007
David Ahern6810fc92013-08-28 22:29:52 -06002008static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002009 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002010 struct perf_sample *sample,
2011 struct perf_evsel *evsel,
2012 struct machine *machine __maybe_unused)
2013{
2014 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002015 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002016 int err = 0;
2017
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002018 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002019
David Ahernaa07df62016-11-25 09:29:52 -07002020 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2021 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002022 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002023
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002024 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002025
David Ahern31605652013-12-04 19:41:41 -07002026 if (handler) {
2027 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002028 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002029 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002030out:
2031 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002032 return err;
2033}
2034
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002035static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002036{
2037 unsigned int rec_argc, i, j;
2038 const char **rec_argv;
2039 const char * const record_args[] = {
2040 "record",
2041 "-R",
2042 "-m", "1024",
2043 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002044 };
2045
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002046 const char * const sc_args[] = { "-e", };
2047 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2048 const char * const majpf_args[] = { "-e", "major-faults" };
2049 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2050 const char * const minpf_args[] = { "-e", "minor-faults" };
2051 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2052
David Ahern9aca7f12013-12-04 19:41:39 -07002053 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002054 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2055 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002056 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2057
2058 if (rec_argv == NULL)
2059 return -ENOMEM;
2060
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002061 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002062 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002063 rec_argv[j++] = record_args[i];
2064
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002065 if (trace->trace_syscalls) {
2066 for (i = 0; i < sc_args_nr; i++)
2067 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002068
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002069 /* event string may be different for older kernels - e.g., RHEL6 */
2070 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2071 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2072 else if (is_valid_tracepoint("syscalls:sys_enter"))
2073 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2074 else {
2075 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2076 return -1;
2077 }
David Ahern9aca7f12013-12-04 19:41:39 -07002078 }
David Ahern9aca7f12013-12-04 19:41:39 -07002079
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002080 if (trace->trace_pgfaults & TRACE_PFMAJ)
2081 for (i = 0; i < majpf_args_nr; i++)
2082 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002083
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002084 if (trace->trace_pgfaults & TRACE_PFMIN)
2085 for (i = 0; i < minpf_args_nr; i++)
2086 rec_argv[j++] = minpf_args[i];
2087
2088 for (i = 0; i < (unsigned int)argc; i++)
2089 rec_argv[j++] = argv[i];
2090
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002091 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002092}
2093
David Ahernbf2575c2013-10-08 21:26:53 -06002094static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2095
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002096static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002097{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002098 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002099
2100 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002101 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002102
2103 if (perf_evsel__field(evsel, "pathname") == NULL) {
2104 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002105 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002106 }
2107
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002108 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002109 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002110 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002111}
2112
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002113static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002114{
2115 struct perf_evsel *evsel;
2116 struct perf_event_attr attr = {
2117 .type = PERF_TYPE_SOFTWARE,
2118 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002119 };
2120
2121 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002122 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002123
2124 event_attr_init(&attr);
2125
2126 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002127 if (evsel)
2128 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002129
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002130 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002131}
2132
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002133static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2134{
2135 const u32 type = event->header.type;
2136 struct perf_evsel *evsel;
2137
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002138 if (type != PERF_RECORD_SAMPLE) {
2139 trace__process_event(trace, trace->host, event, sample);
2140 return;
2141 }
2142
2143 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2144 if (evsel == NULL) {
2145 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2146 return;
2147 }
2148
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002149 trace__set_base_time(trace, evsel, sample);
2150
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002151 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2152 sample->raw_data == NULL) {
2153 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2154 perf_evsel__name(evsel), sample->tid,
2155 sample->cpu, sample->raw_size);
2156 } else {
2157 tracepoint_handler handler = evsel->handler;
2158 handler(trace, evsel, event, sample);
2159 }
2160}
2161
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002162static int trace__add_syscall_newtp(struct trace *trace)
2163{
2164 int ret = -1;
2165 struct perf_evlist *evlist = trace->evlist;
2166 struct perf_evsel *sys_enter, *sys_exit;
2167
2168 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2169 if (sys_enter == NULL)
2170 goto out;
2171
2172 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2173 goto out_delete_sys_enter;
2174
2175 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2176 if (sys_exit == NULL)
2177 goto out_delete_sys_enter;
2178
2179 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2180 goto out_delete_sys_exit;
2181
2182 perf_evlist__add(evlist, sys_enter);
2183 perf_evlist__add(evlist, sys_exit);
2184
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002185 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002186 /*
2187 * We're interested only in the user space callchain
2188 * leading to the syscall, allow overriding that for
2189 * debugging reasons using --kernel_syscall_callchains
2190 */
2191 sys_exit->attr.exclude_callchain_kernel = 1;
2192 }
2193
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002194 trace->syscalls.events.sys_enter = sys_enter;
2195 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002196
2197 ret = 0;
2198out:
2199 return ret;
2200
2201out_delete_sys_exit:
2202 perf_evsel__delete_priv(sys_exit);
2203out_delete_sys_enter:
2204 perf_evsel__delete_priv(sys_enter);
2205 goto out;
2206}
2207
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002208static int trace__set_ev_qualifier_filter(struct trace *trace)
2209{
2210 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002211 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002212 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2213 trace->ev_qualifier_ids.nr,
2214 trace->ev_qualifier_ids.entries);
2215
2216 if (filter == NULL)
2217 goto out_enomem;
2218
Mathieu Poirier3541c032016-09-16 08:44:04 -06002219 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2220 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002221 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002222 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002223 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002224
2225 free(filter);
2226out:
2227 return err;
2228out_enomem:
2229 errno = ENOMEM;
2230 goto out;
2231}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002232
Namhyung Kimf15eb532012-10-05 14:02:16 +09002233static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002234{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002235 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002236 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002237 int err = -1, i;
2238 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002239 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002240 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002241
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002242 trace->live = true;
2243
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002244 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002245 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002246
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002247 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002248 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002249
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002250 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2251 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2252 if (pgfault_maj == NULL)
2253 goto out_error_mem;
2254 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002255 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002256
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002257 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2258 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2259 if (pgfault_min == NULL)
2260 goto out_error_mem;
2261 perf_evlist__add(evlist, pgfault_min);
2262 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002263
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002264 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002265 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2266 trace__sched_stat_runtime))
2267 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002268
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002269 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2270 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002271 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002272 goto out_delete_evlist;
2273 }
2274
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002275 err = trace__symbols_init(trace, evlist);
2276 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002277 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002278 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002279 }
2280
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002281 perf_evlist__config(evlist, &trace->opts, NULL);
2282
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002283 if (callchain_param.enabled) {
2284 bool use_identifier = false;
2285
2286 if (trace->syscalls.events.sys_exit) {
2287 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2288 &trace->opts, &callchain_param);
2289 use_identifier = true;
2290 }
2291
2292 if (pgfault_maj) {
2293 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2294 use_identifier = true;
2295 }
2296
2297 if (pgfault_min) {
2298 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2299 use_identifier = true;
2300 }
2301
2302 if (use_identifier) {
2303 /*
2304 * Now we have evsels with different sample_ids, use
2305 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2306 * from a fixed position in each ring buffer record.
2307 *
2308 * As of this the changeset introducing this comment, this
2309 * isn't strictly needed, as the fields that can come before
2310 * PERF_SAMPLE_ID are all used, but we'll probably disable
2311 * some of those for things like copying the payload of
2312 * pointer syscall arguments, and for vfs_getname we don't
2313 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2314 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2315 */
2316 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2317 perf_evlist__reset_sample_bit(evlist, ID);
2318 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002319 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002320
Namhyung Kimf15eb532012-10-05 14:02:16 +09002321 signal(SIGCHLD, sig_handler);
2322 signal(SIGINT, sig_handler);
2323
2324 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002325 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002326 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002327 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002328 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002329 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002330 }
2331 }
2332
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002334 if (err < 0)
2335 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002336
Wang Nanba504232016-02-26 09:31:54 +00002337 err = bpf__apply_obj_config();
2338 if (err) {
2339 char errbuf[BUFSIZ];
2340
2341 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2342 pr_err("ERROR: Apply config to BPF failed: %s\n",
2343 errbuf);
2344 goto out_error_open;
2345 }
2346
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002347 /*
2348 * Better not use !target__has_task() here because we need to cover the
2349 * case where no threads were specified in the command line, but a
2350 * workload was, and in that case we will fill in the thread_map when
2351 * we fork the workload in perf_evlist__prepare_workload.
2352 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002353 if (trace->filter_pids.nr > 0)
2354 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002355 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002356 err = perf_evlist__set_filter_pid(evlist, getpid());
2357
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002358 if (err < 0)
2359 goto out_error_mem;
2360
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002361 if (trace->ev_qualifier_ids.nr > 0) {
2362 err = trace__set_ev_qualifier_filter(trace);
2363 if (err < 0)
2364 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002365
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002366 pr_debug("event qualifier tracepoint filter: %s\n",
2367 trace->syscalls.events.sys_exit->filter);
2368 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002369
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002370 err = perf_evlist__apply_filters(evlist, &evsel);
2371 if (err < 0)
2372 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002373
Jiri Olsaf8850372013-11-28 17:57:22 +01002374 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002375 if (err < 0)
2376 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002377
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002378 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002379 perf_evlist__enable(evlist);
2380
Namhyung Kimf15eb532012-10-05 14:02:16 +09002381 if (forks)
2382 perf_evlist__start_workload(evlist);
2383
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002384 if (trace->opts.initial_delay) {
2385 usleep(trace->opts.initial_delay * 1000);
2386 perf_evlist__enable(evlist);
2387 }
2388
Jiri Olsae13798c2015-06-23 00:36:02 +02002389 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002390 evlist->threads->nr > 1 ||
2391 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002393 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002394
2395 for (i = 0; i < evlist->nr_mmaps; i++) {
2396 union perf_event *event;
2397
2398 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002399 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002400
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002401 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002402
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002403 err = perf_evlist__parse_sample(evlist, event, &sample);
2404 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002405 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002406 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002407 }
2408
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002409 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002410next_event:
2411 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002412
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002413 if (interrupted)
2414 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002415
2416 if (done && !draining) {
2417 perf_evlist__disable(evlist);
2418 draining = true;
2419 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002420 }
2421 }
2422
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002423 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002424 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002425
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002426 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2427 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2428 draining = true;
2429
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002430 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002431 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002432 } else {
2433 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002434 }
2435
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002436out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002437 thread__zput(trace->current);
2438
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002439 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002440
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002441 if (!err) {
2442 if (trace->summary)
2443 trace__fprintf_thread_summary(trace, trace->output);
2444
2445 if (trace->show_tool_stats) {
2446 fprintf(trace->output, "Stats:\n "
2447 " vfs_getname : %" PRIu64 "\n"
2448 " proc_getname: %" PRIu64 "\n",
2449 trace->stats.vfs_getname,
2450 trace->stats.proc_getname);
2451 }
2452 }
David Ahernbf2575c2013-10-08 21:26:53 -06002453
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002454out_delete_evlist:
2455 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002456 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002457 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002458 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002459{
2460 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002461
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002462out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002463 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002464 goto out_error;
2465
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002466out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002467 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002468 goto out_error;
2469
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002470out_error_mmap:
2471 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2472 goto out_error;
2473
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002474out_error_open:
2475 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2476
2477out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002478 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302479 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002480
2481out_error_apply_filters:
2482 fprintf(trace->output,
2483 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2484 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002485 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002486 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002487}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002488out_error_mem:
2489 fprintf(trace->output, "Not enough memory to run!\n");
2490 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002491
2492out_errno:
2493 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2494 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002495}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002496
David Ahern6810fc92013-08-28 22:29:52 -06002497static int trace__replay(struct trace *trace)
2498{
2499 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002500 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002501 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002502 struct perf_data_file file = {
2503 .path = input_name,
2504 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002505 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002506 };
David Ahern6810fc92013-08-28 22:29:52 -06002507 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002508 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002509 int err = -1;
2510
2511 trace->tool.sample = trace__process_sample;
2512 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002513 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002514 trace->tool.comm = perf_event__process_comm;
2515 trace->tool.exit = perf_event__process_exit;
2516 trace->tool.fork = perf_event__process_fork;
2517 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302518 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002519 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302520 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002521
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002522 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002523 trace->tool.ordering_requires_timestamps = true;
2524
2525 /* add tid to output */
2526 trace->multiple_threads = true;
2527
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002528 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002529 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002530 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002531
David Ahernaa07df62016-11-25 09:29:52 -07002532 if (trace->opts.target.pid)
2533 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2534
2535 if (trace->opts.target.tid)
2536 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2537
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002538 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002539 goto out;
2540
David Ahern8fb598e2013-09-28 13:13:00 -06002541 trace->host = &session->machines.host;
2542
David Ahern6810fc92013-08-28 22:29:52 -06002543 err = perf_session__set_tracepoints_handlers(session, handlers);
2544 if (err)
2545 goto out;
2546
Namhyung Kim003824e2013-11-12 15:25:00 +09002547 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2548 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002549 /* older kernels have syscalls tp versus raw_syscalls */
2550 if (evsel == NULL)
2551 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2552 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002553
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002554 if (evsel &&
2555 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2556 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002557 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2558 goto out;
2559 }
2560
2561 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2562 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002563 if (evsel == NULL)
2564 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2565 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002566 if (evsel &&
2567 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2568 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002569 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002570 goto out;
2571 }
2572
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002573 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002574 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2575 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2576 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2577 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2578 evsel->handler = trace__pgfault;
2579 }
2580
David Ahern6810fc92013-08-28 22:29:52 -06002581 setup_pager();
2582
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002583 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002584 if (err)
2585 pr_err("Failed to process events, error %d", err);
2586
David Ahernbf2575c2013-10-08 21:26:53 -06002587 else if (trace->summary)
2588 trace__fprintf_thread_summary(trace, trace->output);
2589
David Ahern6810fc92013-08-28 22:29:52 -06002590out:
2591 perf_session__delete(session);
2592
2593 return err;
2594}
2595
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002596static size_t trace__fprintf_threads_header(FILE *fp)
2597{
2598 size_t printed;
2599
Pekka Enberg99ff7152013-11-12 16:42:14 +02002600 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002601
2602 return printed;
2603}
2604
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002605DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2606 struct stats *stats;
2607 double msecs;
2608 int syscall;
2609)
2610{
2611 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2612 struct stats *stats = source->priv;
2613
2614 entry->syscall = source->i;
2615 entry->stats = stats;
2616 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2617}
2618
David Ahernbf2575c2013-10-08 21:26:53 -06002619static size_t thread__dump_stats(struct thread_trace *ttrace,
2620 struct trace *trace, FILE *fp)
2621{
David Ahernbf2575c2013-10-08 21:26:53 -06002622 size_t printed = 0;
2623 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002624 struct rb_node *nd;
2625 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002626
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002627 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002628 return 0;
2629
2630 printed += fprintf(fp, "\n");
2631
Milian Wolff834fd462015-08-06 11:24:29 +02002632 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2633 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2634 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002635
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002636 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002637 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002638 if (stats) {
2639 double min = (double)(stats->min) / NSEC_PER_MSEC;
2640 double max = (double)(stats->max) / NSEC_PER_MSEC;
2641 double avg = avg_stats(stats);
2642 double pct;
2643 u64 n = (u64) stats->n;
2644
2645 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2646 avg /= NSEC_PER_MSEC;
2647
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002648 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002649 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002650 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002651 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002652 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002653 }
David Ahernbf2575c2013-10-08 21:26:53 -06002654 }
2655
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002656 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002657 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002658
2659 return printed;
2660}
2661
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002662static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002663{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002664 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002665 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002666 double ratio;
2667
2668 if (ttrace == NULL)
2669 return 0;
2670
2671 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2672
Pekka Enberg15e65c62013-11-14 18:43:30 +02002673 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002674 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002675 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002676 if (ttrace->pfmaj)
2677 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2678 if (ttrace->pfmin)
2679 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002680 if (trace->sched)
2681 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2682 else if (fputc('\n', fp) != EOF)
2683 ++printed;
2684
David Ahernbf2575c2013-10-08 21:26:53 -06002685 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002686
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002687 return printed;
2688}
David Ahern896cbb52013-09-28 13:12:59 -06002689
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002690static unsigned long thread__nr_events(struct thread_trace *ttrace)
2691{
2692 return ttrace ? ttrace->nr_events : 0;
2693}
2694
2695DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2696 struct thread *thread;
2697)
2698{
2699 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002700}
2701
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002702static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2703{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002704 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2705 size_t printed = trace__fprintf_threads_header(fp);
2706 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002707
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002708 if (threads == NULL) {
2709 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2710 return 0;
2711 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002712
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002713 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002714 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2715
2716 resort_rb__delete(threads);
2717
2718 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002719}
2720
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002721static int trace__set_duration(const struct option *opt, const char *str,
2722 int unset __maybe_unused)
2723{
2724 struct trace *trace = opt->value;
2725
2726 trace->duration_filter = atof(str);
2727 return 0;
2728}
2729
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002730static int trace__set_filter_pids(const struct option *opt, const char *str,
2731 int unset __maybe_unused)
2732{
2733 int ret = -1;
2734 size_t i;
2735 struct trace *trace = opt->value;
2736 /*
2737 * FIXME: introduce a intarray class, plain parse csv and create a
2738 * { int nr, int entries[] } struct...
2739 */
2740 struct intlist *list = intlist__new(str);
2741
2742 if (list == NULL)
2743 return -1;
2744
2745 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2746 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2747
2748 if (trace->filter_pids.entries == NULL)
2749 goto out;
2750
2751 trace->filter_pids.entries[0] = getpid();
2752
2753 for (i = 1; i < trace->filter_pids.nr; ++i)
2754 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2755
2756 intlist__delete(list);
2757 ret = 0;
2758out:
2759 return ret;
2760}
2761
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002762static int trace__open_output(struct trace *trace, const char *filename)
2763{
2764 struct stat st;
2765
2766 if (!stat(filename, &st) && st.st_size) {
2767 char oldname[PATH_MAX];
2768
2769 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2770 unlink(oldname);
2771 rename(filename, oldname);
2772 }
2773
2774 trace->output = fopen(filename, "w");
2775
2776 return trace->output == NULL ? -errno : 0;
2777}
2778
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002779static int parse_pagefaults(const struct option *opt, const char *str,
2780 int unset __maybe_unused)
2781{
2782 int *trace_pgfaults = opt->value;
2783
2784 if (strcmp(str, "all") == 0)
2785 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2786 else if (strcmp(str, "maj") == 0)
2787 *trace_pgfaults |= TRACE_PFMAJ;
2788 else if (strcmp(str, "min") == 0)
2789 *trace_pgfaults |= TRACE_PFMIN;
2790 else
2791 return -1;
2792
2793 return 0;
2794}
2795
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002796static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2797{
2798 struct perf_evsel *evsel;
2799
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002800 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002801 evsel->handler = handler;
2802}
2803
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002804/*
2805 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2806 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2807 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2808 *
2809 * It'd be better to introduce a parse_options() variant that would return a
2810 * list with the terms it didn't match to an event...
2811 */
2812static int trace__parse_events_option(const struct option *opt, const char *str,
2813 int unset __maybe_unused)
2814{
2815 struct trace *trace = (struct trace *)opt->value;
2816 const char *s = str;
2817 char *sep = NULL, *lists[2] = { NULL, NULL, };
2818 int len = strlen(str), err = -1, list;
2819 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2820 char group_name[PATH_MAX];
2821
2822 if (strace_groups_dir == NULL)
2823 return -1;
2824
2825 if (*s == '!') {
2826 ++s;
2827 trace->not_ev_qualifier = true;
2828 }
2829
2830 while (1) {
2831 if ((sep = strchr(s, ',')) != NULL)
2832 *sep = '\0';
2833
2834 list = 0;
2835 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2836 list = 1;
2837 } else {
2838 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2839 if (access(group_name, R_OK) == 0)
2840 list = 1;
2841 }
2842
2843 if (lists[list]) {
2844 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2845 } else {
2846 lists[list] = malloc(len);
2847 if (lists[list] == NULL)
2848 goto out;
2849 strcpy(lists[list], s);
2850 }
2851
2852 if (!sep)
2853 break;
2854
2855 *sep = ',';
2856 s = sep + 1;
2857 }
2858
2859 if (lists[1] != NULL) {
2860 struct strlist_config slist_config = {
2861 .dirname = strace_groups_dir,
2862 };
2863
2864 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2865 if (trace->ev_qualifier == NULL) {
2866 fputs("Not enough memory to parse event qualifier", trace->output);
2867 goto out;
2868 }
2869
2870 if (trace__validate_ev_qualifier(trace))
2871 goto out;
2872 }
2873
2874 err = 0;
2875
2876 if (lists[0]) {
2877 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2878 "event selector. use 'perf list' to list available events",
2879 parse_events_option);
2880 err = parse_events_option(&o, lists[0], 0);
2881 }
2882out:
2883 if (sep)
2884 *sep = ',';
2885
2886 return err;
2887}
2888
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002889int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002890{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002891 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002892 "perf trace [<options>] [<command>]",
2893 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002894 "perf trace record [<options>] [<command>]",
2895 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002896 NULL
2897 };
2898 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002899 .syscalls = {
2900 . max = -1,
2901 },
2902 .opts = {
2903 .target = {
2904 .uid = UINT_MAX,
2905 .uses_mmap = true,
2906 },
2907 .user_freq = UINT_MAX,
2908 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002909 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002910 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002911 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002912 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002913 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002914 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002915 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002916 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002917 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002918 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002919 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002920 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002921 OPT_CALLBACK('e', "event", &trace, "event",
2922 "event/syscall selector. use 'perf list' to list available events",
2923 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002924 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2925 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002926 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002927 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2928 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002929 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002930 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002931 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2932 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002933 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002934 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002935 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2936 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002937 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002938 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002939 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002940 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002941 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002942 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002943 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2944 "number of mmap data pages",
2945 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002946 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002947 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002948 OPT_CALLBACK(0, "duration", &trace, "float",
2949 "show only events with duration > N.M ms",
2950 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002951 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002952 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002953 OPT_BOOLEAN('T', "time", &trace.full_time,
2954 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002955 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2956 "Show only syscall summary with statistics"),
2957 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2958 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002959 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2960 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002961 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002962 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002963 OPT_CALLBACK(0, "call-graph", &trace.opts,
2964 "record_mode[,record_size]", record_callchain_help,
2965 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002966 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2967 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002968 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2969 "Set the minimum stack depth when parsing the callchain, "
2970 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002971 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2972 "Set the maximum stack depth when parsing the callchain, "
2973 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002974 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002975 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2976 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002977 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2978 "ms to wait before starting measurement after program "
2979 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002980 OPT_END()
2981 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002982 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002983 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002984 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002985 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002986 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002987
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002988 signal(SIGSEGV, sighandler_dump_stack);
2989 signal(SIGFPE, sighandler_dump_stack);
2990
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002991 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002992 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002993
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002994 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002995 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002996 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002997 goto out;
2998 }
2999
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003000 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3001 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003002
Wang Nand7888572016-04-08 15:07:24 +00003003 err = bpf__setup_stdout(trace.evlist);
3004 if (err) {
3005 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3006 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3007 goto out;
3008 }
3009
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003010 err = -1;
3011
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003012 if (trace.trace_pgfaults) {
3013 trace.opts.sample_address = true;
3014 trace.opts.sample_time = true;
3015 }
3016
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003017 if (trace.opts.mmap_pages == UINT_MAX)
3018 mmap_pages_user_set = false;
3019
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003020 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003021 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003022 max_stack_user_set = false;
3023 }
3024
3025#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003026 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003027 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3028#endif
3029
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003030 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003031 if (!mmap_pages_user_set && geteuid() == 0)
3032 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3033
Milian Wolff566a0882016-04-08 13:34:15 +02003034 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003035 }
Milian Wolff566a0882016-04-08 13:34:15 +02003036
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003037 if (trace.evlist->nr_entries > 0)
3038 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3039
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003040 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3041 return trace__record(&trace, argc-1, &argv[1]);
3042
3043 /* summary_only implies summary option, but don't overwrite summary if set */
3044 if (trace.summary_only)
3045 trace.summary = trace.summary_only;
3046
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003047 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3048 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003049 pr_err("Please specify something to trace.\n");
3050 return -1;
3051 }
3052
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003053 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003054 pr_err("The -e option can't be used with --no-syscalls.\n");
3055 goto out;
3056 }
3057
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003058 if (output_name != NULL) {
3059 err = trace__open_output(&trace, output_name);
3060 if (err < 0) {
3061 perror("failed to create output file");
3062 goto out;
3063 }
3064 }
3065
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003066 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3067
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003068 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003069 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003070 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003071 fprintf(trace.output, "%s", bf);
3072 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003073 }
3074
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003075 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003076 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003077 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003078 fprintf(trace.output, "%s", bf);
3079 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003080 }
3081
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003082 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003083 trace.opts.target.system_wide = true;
3084
David Ahern6810fc92013-08-28 22:29:52 -06003085 if (input_name)
3086 err = trace__replay(&trace);
3087 else
3088 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003089
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003090out_close:
3091 if (output_name != NULL)
3092 fclose(trace.output);
3093out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003094 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003095}