blob: a323736043e1546c1722410cc5b2ca4c722f6584 [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",
452};
453
454static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
455
456static struct strarray *fcntl_cmds_arrays[] = {
457 &strarray__fcntl_cmds,
458 &strarray__fcntl_linux_specific_cmds,
459};
460
461static DEFINE_STRARRAYS(fcntl_cmds_arrays);
462
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300463static const char *rlimit_resources[] = {
464 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
465 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
466 "RTTIME",
467};
468static DEFINE_STRARRAY(rlimit_resources);
469
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300470static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
471static DEFINE_STRARRAY(sighow);
472
David Ahern4f8c1b72013-09-22 19:45:00 -0600473static const char *clockid[] = {
474 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300475 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
476 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600477};
478static DEFINE_STRARRAY(clockid);
479
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300480static const char *socket_families[] = {
481 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
482 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
483 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
484 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
485 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
486 "ALG", "NFC", "VSOCK",
487};
488static DEFINE_STRARRAY(socket_families);
489
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300490static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
491 struct syscall_arg *arg)
492{
493 size_t printed = 0;
494 int mode = arg->val;
495
496 if (mode == F_OK) /* 0 */
497 return scnprintf(bf, size, "F");
498#define P_MODE(n) \
499 if (mode & n##_OK) { \
500 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
501 mode &= ~n##_OK; \
502 }
503
504 P_MODE(R);
505 P_MODE(W);
506 P_MODE(X);
507#undef P_MODE
508
509 if (mode)
510 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
511
512 return printed;
513}
514
515#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
516
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300517static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
518 struct syscall_arg *arg);
519
520#define SCA_FILENAME syscall_arg__scnprintf_filename
521
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300522static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
523 struct syscall_arg *arg)
524{
525 int printed = 0, flags = arg->val;
526
527#define P_FLAG(n) \
528 if (flags & O_##n) { \
529 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
530 flags &= ~O_##n; \
531 }
532
533 P_FLAG(CLOEXEC);
534 P_FLAG(NONBLOCK);
535#undef P_FLAG
536
537 if (flags)
538 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
539
540 return printed;
541}
542
543#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
544
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300545#if defined(__i386__) || defined(__x86_64__)
546/*
547 * FIXME: Make this available to all arches.
548 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300549#define TCGETS 0x5401
550
551static const char *tioctls[] = {
552 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
553 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
554 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
555 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
556 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
557 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
558 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
559 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
560 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
561 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
562 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
563 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
564 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
565 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
566 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
567};
568
569static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300570#endif /* defined(__i386__) || defined(__x86_64__) */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300571
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300572#ifndef GRND_NONBLOCK
573#define GRND_NONBLOCK 0x0001
574#endif
575#ifndef GRND_RANDOM
576#define GRND_RANDOM 0x0002
577#endif
578
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300579static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
580 struct syscall_arg *arg)
581{
582 int printed = 0, flags = arg->val;
583
584#define P_FLAG(n) \
585 if (flags & GRND_##n) { \
586 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
587 flags &= ~GRND_##n; \
588 }
589
590 P_FLAG(RANDOM);
591 P_FLAG(NONBLOCK);
592#undef P_FLAG
593
594 if (flags)
595 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
596
597 return printed;
598}
599
600#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
601
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300602#define STRARRAY(arg, name, array) \
603 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
604 .arg_parm = { [arg] = &strarray__##array, }
605
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300606#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melo8bf382c2016-05-11 10:29:36 -0300607#include "trace/beauty/flock.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300608#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300609#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300610#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300611#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300612#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300613#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300614#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300615#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300616#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300617#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300618#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300619#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300620
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300621static struct syscall_fmt {
622 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300623 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300624 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300625 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300626 bool errmsg;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300627 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300628 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300629 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300630} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300631 { .name = "access", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300632 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300633 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300634 { .name = "bpf", .errmsg = true, STRARRAY(0, cmd, bpf_cmd), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300635 { .name = "brk", .hexret = true,
636 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300637 { .name = "chdir", .errmsg = true, },
638 { .name = "chmod", .errmsg = true, },
639 { .name = "chroot", .errmsg = true, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600640 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300641 { .name = "clone", .errpid = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300642 { .name = "close", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300643 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300644 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300645 { .name = "creat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300646 { .name = "dup", .errmsg = true, },
647 { .name = "dup2", .errmsg = true, },
648 { .name = "dup3", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300649 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300650 { .name = "eventfd2", .errmsg = true,
651 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300652 { .name = "faccessat", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300653 { .name = "fadvise64", .errmsg = true, },
654 { .name = "fallocate", .errmsg = true, },
655 { .name = "fchdir", .errmsg = true, },
656 { .name = "fchmod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300657 { .name = "fchmodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300658 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300659 { .name = "fchown", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300660 { .name = "fchownat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300661 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300662 { .name = "fcntl", .errmsg = true,
Arnaldo Carvalho de Melo9cb7cf82017-07-14 09:44:50 -0300663 .arg_scnprintf = { [1] = SCA_FCNTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300664 .arg_parm = { [1] = &strarrays__fcntl_cmds_arrays, /* cmd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300665 { .name = "fdatasync", .errmsg = true, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300666 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300667 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
668 { .name = "fsetxattr", .errmsg = true, },
669 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300670 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300671 { .name = "fstatfs", .errmsg = true, },
672 { .name = "fsync", .errmsg = true, },
673 { .name = "ftruncate", .errmsg = true, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300674 { .name = "futex", .errmsg = true,
675 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300676 { .name = "futimesat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300677 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300678 { .name = "getdents", .errmsg = true, },
679 { .name = "getdents64", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300680 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300681 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300682 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300683 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300684 { .name = "getrandom", .errmsg = true,
685 .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300686 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300687 { .name = "getxattr", .errmsg = true, },
688 { .name = "inotify_add_watch", .errmsg = true, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300689 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300690 .arg_scnprintf = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300691#if defined(__i386__) || defined(__x86_64__)
692/*
693 * FIXME: Make this available to all arches.
694 */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300695 [1] = SCA_STRHEXARRAY, /* cmd */
696 [2] = SCA_HEX, /* arg */ },
697 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300698#else
699 [2] = SCA_HEX, /* arg */ }, },
700#endif
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300701 { .name = "keyctl", .errmsg = true, STRARRAY(0, option, keyctl_options), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300702 { .name = "kill", .errmsg = true,
703 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300704 { .name = "lchown", .errmsg = true, },
705 { .name = "lgetxattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300706 { .name = "linkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300707 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300708 { .name = "listxattr", .errmsg = true, },
709 { .name = "llistxattr", .errmsg = true, },
710 { .name = "lremovexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300711 { .name = "lseek", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300712 .arg_scnprintf = { [2] = SCA_STRARRAY, /* whence */ },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300713 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300714 { .name = "lsetxattr", .errmsg = true, },
715 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
716 { .name = "lsxattr", .errmsg = true, },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300717 { .name = "madvise", .errmsg = true,
718 .arg_scnprintf = { [0] = SCA_HEX, /* start */
719 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300720 { .name = "mkdir", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300721 { .name = "mkdirat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300722 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
723 { .name = "mknod", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300724 { .name = "mknodat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300725 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300726 { .name = "mlock", .errmsg = true,
727 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
728 { .name = "mlockall", .errmsg = true,
729 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300730 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200731/* The standard mmap maps to old_mmap on s390x */
732#if defined(__s390x__)
733 .alias = "old_mmap",
734#endif
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300735 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300736 [2] = SCA_MMAP_PROT, /* prot */
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300737 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300738 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300739 .arg_scnprintf = { [0] = SCA_HEX, /* start */
740 [2] = SCA_MMAP_PROT, /* prot */ }, },
Arnaldo Carvalho de Melo090389b62015-08-10 19:20:52 -0300741 { .name = "mq_unlink", .errmsg = true,
742 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300743 { .name = "mremap", .hexret = true,
744 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Alex Snast86998dd2014-08-13 18:42:40 +0300745 [3] = SCA_MREMAP_FLAGS, /* flags */
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300746 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300747 { .name = "munlock", .errmsg = true,
748 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300749 { .name = "munmap", .errmsg = true,
750 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300751 { .name = "name_to_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300752 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300753 { .name = "newfstatat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300754 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300755 { .name = "open", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300756 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300757 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300758 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
759 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300760 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300761 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
762 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300763 { .name = "perf_event_open", .errmsg = true,
Arnaldo Carvalho de Meloccd9b2a2016-04-26 11:40:17 -0300764 .arg_scnprintf = { [2] = SCA_INT, /* cpu */
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300765 [3] = SCA_FD, /* group_fd */
766 [4] = SCA_PERF_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300767 { .name = "pipe2", .errmsg = true,
768 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300769 { .name = "poll", .errmsg = true, .timeout = true, },
770 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300771 { .name = "pread", .errmsg = true, .alias = "pread64", },
772 { .name = "preadv", .errmsg = true, .alias = "pread", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300773 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300774 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
775 { .name = "pwritev", .errmsg = true, },
776 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300777 { .name = "readlink", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300778 { .name = "readlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300779 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300780 { .name = "readv", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300781 { .name = "recvfrom", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300782 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300783 { .name = "recvmmsg", .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 = "recvmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300786 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300787 { .name = "removexattr", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300788 { .name = "renameat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300789 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300790 { .name = "rmdir", .errmsg = true, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300791 { .name = "rt_sigaction", .errmsg = true,
792 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300793 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300794 { .name = "rt_sigqueueinfo", .errmsg = true,
795 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
796 { .name = "rt_tgsigqueueinfo", .errmsg = true,
797 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melof0bbd602016-09-28 13:45:38 -0300798 { .name = "sched_getattr", .errmsg = true, },
799 { .name = "sched_setattr", .errmsg = true, },
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300800 { .name = "sched_setscheduler", .errmsg = true,
801 .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, },
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -0300802 { .name = "seccomp", .errmsg = true,
803 .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */
804 [1] = SCA_SECCOMP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300805 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300806 { .name = "sendmmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300807 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300808 { .name = "sendmsg", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300809 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300810 { .name = "sendto", .errmsg = true,
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300811 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300812 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300813 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300814 { .name = "setpgid", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300815 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300816 { .name = "setxattr", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300817 { .name = "shutdown", .errmsg = true, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300818 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300819 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
820 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300821 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300822 { .name = "socketpair", .errmsg = true,
823 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
824 [1] = SCA_SK_TYPE, /* type */ },
825 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300826 { .name = "stat", .errmsg = true, .alias = "newstat", },
827 { .name = "statfs", .errmsg = true, },
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -0300828 { .name = "statx", .errmsg = true,
829 .arg_scnprintf = { [0] = SCA_FDAT, /* flags */
830 [2] = SCA_STATX_FLAGS, /* flags */
831 [3] = SCA_STATX_MASK, /* mask */ }, },
Arnaldo Carvalho de Melo34221112015-08-04 23:31:25 -0300832 { .name = "swapoff", .errmsg = true,
833 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
834 { .name = "swapon", .errmsg = true,
835 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300836 { .name = "symlinkat", .errmsg = true,
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300837 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300838 { .name = "tgkill", .errmsg = true,
839 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
840 { .name = "tkill", .errmsg = true,
841 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300842 { .name = "truncate", .errmsg = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300843 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300844 { .name = "unlinkat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300845 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
846 { .name = "utime", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300847 { .name = "utimensat", .errmsg = true,
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -0300848 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
849 { .name = "utimes", .errmsg = true, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300850 { .name = "vmsplice", .errmsg = true, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300851 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300852 .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300853 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300854 .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, },
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -0300855 { .name = "write", .errmsg = true, },
856 { .name = "writev", .errmsg = true, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300857};
858
859static int syscall_fmt__cmp(const void *name, const void *fmtp)
860{
861 const struct syscall_fmt *fmt = fmtp;
862 return strcmp(name, fmt->name);
863}
864
865static struct syscall_fmt *syscall_fmt__find(const char *name)
866{
867 const int nmemb = ARRAY_SIZE(syscall_fmts);
868 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
869}
870
871struct syscall {
872 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300873 int nr_args;
874 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300875 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300876 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300877 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300878 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300879 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300880};
881
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300882/*
883 * We need to have this 'calculated' boolean because in some cases we really
884 * don't know what is the duration of a syscall, for instance, when we start
885 * a session and some threads are waiting for a syscall to finish, say 'poll',
886 * in which case all we can do is to print "( ? ) for duration and for the
887 * start timestamp.
888 */
889static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200890{
891 double duration = (double)t / NSEC_PER_MSEC;
892 size_t printed = fprintf(fp, "(");
893
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300894 if (!calculated)
895 printed += fprintf(fp, " ? ");
896 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200897 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
898 else if (duration >= 0.01)
899 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
900 else
901 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300902 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200903}
904
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300905/**
906 * filename.ptr: The filename char pointer that will be vfs_getname'd
907 * filename.entry_str_pos: Where to insert the string translated from
908 * filename.ptr by the vfs_getname tracepoint/kprobe.
909 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300910struct thread_trace {
911 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300913 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400914 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300915 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300916 double runtime_ms;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300917 struct {
918 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300919 short int entry_str_pos;
920 bool pending_open;
921 unsigned int namelen;
922 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300923 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300924 struct {
925 int max;
926 char **table;
927 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600928
929 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300930};
931
932static struct thread_trace *thread_trace__new(void)
933{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300934 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
935
936 if (ttrace)
937 ttrace->paths.max = -1;
938
David Ahernbf2575c2013-10-08 21:26:53 -0600939 ttrace->syscall_stats = intlist__new(NULL);
940
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300941 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300942}
943
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300944static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300945{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300946 struct thread_trace *ttrace;
947
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300948 if (thread == NULL)
949 goto fail;
950
Namhyung Kim89dceb22014-10-06 09:46:03 +0900951 if (thread__priv(thread) == NULL)
952 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300953
Namhyung Kim89dceb22014-10-06 09:46:03 +0900954 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300955 goto fail;
956
Namhyung Kim89dceb22014-10-06 09:46:03 +0900957 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300958 ++ttrace->nr_events;
959
960 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300961fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300962 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300963 "WARNING: not enough memory, dropping samples!\n");
964 return NULL;
965}
966
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400967#define TRACE_PFMAJ (1 << 0)
968#define TRACE_PFMIN (1 << 1)
969
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300970static const size_t trace__entry_str_size = 2048;
971
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300972static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300973{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900974 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300975
976 if (fd > ttrace->paths.max) {
977 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
978
979 if (npath == NULL)
980 return -1;
981
982 if (ttrace->paths.max != -1) {
983 memset(npath + ttrace->paths.max + 1, 0,
984 (fd - ttrace->paths.max) * sizeof(char *));
985 } else {
986 memset(npath, 0, (fd + 1) * sizeof(char *));
987 }
988
989 ttrace->paths.table = npath;
990 ttrace->paths.max = fd;
991 }
992
993 ttrace->paths.table[fd] = strdup(pathname);
994
995 return ttrace->paths.table[fd] != NULL ? 0 : -1;
996}
997
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300998static int thread__read_fd_path(struct thread *thread, int fd)
999{
1000 char linkname[PATH_MAX], pathname[PATH_MAX];
1001 struct stat st;
1002 int ret;
1003
1004 if (thread->pid_ == thread->tid) {
1005 scnprintf(linkname, sizeof(linkname),
1006 "/proc/%d/fd/%d", thread->pid_, fd);
1007 } else {
1008 scnprintf(linkname, sizeof(linkname),
1009 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1010 }
1011
1012 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1013 return -1;
1014
1015 ret = readlink(linkname, pathname, sizeof(pathname));
1016
1017 if (ret < 0 || ret > st.st_size)
1018 return -1;
1019
1020 pathname[ret] = '\0';
1021 return trace__set_fd_pathname(thread, fd, pathname);
1022}
1023
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001024static const char *thread__fd_path(struct thread *thread, int fd,
1025 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001026{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001027 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001028
1029 if (ttrace == NULL)
1030 return NULL;
1031
1032 if (fd < 0)
1033 return NULL;
1034
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001035 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001036 if (!trace->live)
1037 return NULL;
1038 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001039 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001040 return NULL;
1041 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001042
1043 return ttrace->paths.table[fd];
1044}
1045
1046static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1047 struct syscall_arg *arg)
1048{
1049 int fd = arg->val;
1050 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001051 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001052
1053 if (path)
1054 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1055
1056 return printed;
1057}
1058
1059static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1060 struct syscall_arg *arg)
1061{
1062 int fd = arg->val;
1063 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001064 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001065
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001066 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1067 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001068
1069 return printed;
1070}
1071
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001072static void thread__set_filename_pos(struct thread *thread, const char *bf,
1073 unsigned long ptr)
1074{
1075 struct thread_trace *ttrace = thread__priv(thread);
1076
1077 ttrace->filename.ptr = ptr;
1078 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1079}
1080
1081static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1082 struct syscall_arg *arg)
1083{
1084 unsigned long ptr = arg->val;
1085
1086 if (!arg->trace->vfs_getname)
1087 return scnprintf(bf, size, "%#x", ptr);
1088
1089 thread__set_filename_pos(arg->thread, bf, ptr);
1090 return 0;
1091}
1092
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001093static bool trace__filter_duration(struct trace *trace, double t)
1094{
1095 return t < (trace->duration_filter * NSEC_PER_MSEC);
1096}
1097
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001098static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001099{
1100 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1101
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001102 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001103}
1104
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001105/*
1106 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1107 * using ttrace->entry_time for a thread that receives a sys_exit without
1108 * first having received a sys_enter ("poll" issued before tracing session
1109 * starts, lost sys_enter exit due to ring buffer overflow).
1110 */
1111static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1112{
1113 if (tstamp > 0)
1114 return __trace__fprintf_tstamp(trace, tstamp, fp);
1115
1116 return fprintf(fp, " ? ");
1117}
1118
Namhyung Kimf15eb532012-10-05 14:02:16 +09001119static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001120static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001121
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001122static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001123{
1124 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001125 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001126}
1127
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001129 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001130{
1131 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001132 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001133
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001134 if (trace->multiple_threads) {
1135 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001136 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001137 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001138 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001139
1140 return printed;
1141}
1142
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001143static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001144 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145{
1146 int ret = 0;
1147
1148 switch (event->header.type) {
1149 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001150 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001151 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001152 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001153 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001154 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001155 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001156 break;
1157 }
1158
1159 return ret;
1160}
1161
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001162static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001163 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001164 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001165 struct machine *machine)
1166{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001167 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001168 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001169}
1170
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001171static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1172{
1173 struct machine *machine = vmachine;
1174
1175 if (machine->kptr_restrict_warned)
1176 return NULL;
1177
1178 if (symbol_conf.kptr_restrict) {
1179 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1180 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1181 "Kernel samples will not be resolved.\n");
1182 machine->kptr_restrict_warned = true;
1183 return NULL;
1184 }
1185
1186 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1187}
1188
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001189static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1190{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001191 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001192
1193 if (err)
1194 return err;
1195
David Ahern8fb598e2013-09-28 13:13:00 -06001196 trace->host = machine__new_host();
1197 if (trace->host == NULL)
1198 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001199
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001200 if (trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr) < 0)
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001201 return -errno;
1202
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001203 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001204 evlist->threads, trace__tool_process, false,
1205 trace->opts.proc_map_timeout);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001206 if (err)
1207 symbol__exit();
1208
1209 return err;
1210}
1211
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001212static int syscall__set_arg_fmts(struct syscall *sc)
1213{
1214 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001215 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001216
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001217 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001218 if (sc->arg_scnprintf == NULL)
1219 return -1;
1220
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001221 if (sc->fmt)
1222 sc->arg_parm = sc->fmt->arg_parm;
1223
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001224 for (field = sc->args; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001225 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1226 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001227 else if (strcmp(field->type, "const char *") == 0 &&
1228 (strcmp(field->name, "filename") == 0 ||
1229 strcmp(field->name, "path") == 0 ||
1230 strcmp(field->name, "pathname") == 0))
1231 sc->arg_scnprintf[idx] = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001232 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001233 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001234 else if (strcmp(field->type, "pid_t") == 0)
1235 sc->arg_scnprintf[idx] = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001236 else if (strcmp(field->type, "umode_t") == 0)
1237 sc->arg_scnprintf[idx] = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001238 else if ((strcmp(field->type, "int") == 0 ||
1239 strcmp(field->type, "unsigned int") == 0 ||
1240 strcmp(field->type, "long") == 0) &&
1241 (len = strlen(field->name)) >= 2 &&
1242 strcmp(field->name + len - 2, "fd") == 0) {
1243 /*
1244 * /sys/kernel/tracing/events/syscalls/sys_enter*
1245 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1246 * 65 int
1247 * 23 unsigned int
1248 * 7 unsigned long
1249 */
1250 sc->arg_scnprintf[idx] = SCA_FD;
1251 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001252 ++idx;
1253 }
1254
1255 return 0;
1256}
1257
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001258static int trace__read_syscall_info(struct trace *trace, int id)
1259{
1260 char tp_name[128];
1261 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001262 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001263
1264 if (name == NULL)
1265 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001266
1267 if (id > trace->syscalls.max) {
1268 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1269
1270 if (nsyscalls == NULL)
1271 return -1;
1272
1273 if (trace->syscalls.max != -1) {
1274 memset(nsyscalls + trace->syscalls.max + 1, 0,
1275 (id - trace->syscalls.max) * sizeof(*sc));
1276 } else {
1277 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1278 }
1279
1280 trace->syscalls.table = nsyscalls;
1281 trace->syscalls.max = id;
1282 }
1283
1284 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001285 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001286
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001287 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001288
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001289 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001290 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001291
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001292 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001293 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001294 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001295 }
1296
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001297 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001298 return -1;
1299
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001300 sc->args = sc->tp_format->format.fields;
1301 sc->nr_args = sc->tp_format->format.nr_fields;
Taeung Songc42de702016-02-26 22:14:25 +09001302 /*
1303 * We need to check and discard the first variable '__syscall_nr'
1304 * or 'nr' that mean the syscall number. It is needless here.
1305 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1306 */
1307 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001308 sc->args = sc->args->next;
1309 --sc->nr_args;
1310 }
1311
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001312 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1313
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001314 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001315}
1316
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001317static int trace__validate_ev_qualifier(struct trace *trace)
1318{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001319 int err = 0, i;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001320 struct str_node *pos;
1321
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001322 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1323 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1324 sizeof(trace->ev_qualifier_ids.entries[0]));
1325
1326 if (trace->ev_qualifier_ids.entries == NULL) {
1327 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1328 trace->output);
1329 err = -EINVAL;
1330 goto out;
1331 }
1332
1333 i = 0;
1334
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001335 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001336 const char *sc = pos->s;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001337 int id = syscalltbl__id(trace->sctbl, sc);
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001338
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001339 if (id < 0) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001340 if (err == 0) {
1341 fputs("Error:\tInvalid syscall ", trace->output);
1342 err = -EINVAL;
1343 } else {
1344 fputs(", ", trace->output);
1345 }
1346
1347 fputs(sc, trace->output);
1348 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001349
1350 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001351 }
1352
1353 if (err < 0) {
1354 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1355 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001356 zfree(&trace->ev_qualifier_ids.entries);
1357 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001358 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001359out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001360 return err;
1361}
1362
David Ahern55d43bca2015-02-19 15:00:22 -05001363/*
1364 * args is to be interpreted as a series of longs but we need to handle
1365 * 8-byte unaligned accesses. args points to raw_data within the event
1366 * and raw_data is guaranteed to be 8-byte unaligned because it is
1367 * preceded by raw_size which is a u32. So we need to copy args to a temp
1368 * variable to read it. Most notably this avoids extended load instructions
1369 * on unaligned addresses
1370 */
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001371static unsigned long __syscall_arg__val(unsigned char *args, u8 idx)
1372{
1373 unsigned long val;
1374 unsigned char *p = args + sizeof(unsigned long) * idx;
1375
1376 memcpy(&val, p, sizeof(val));
1377 return val;
1378}
1379
1380unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
1381{
1382 return __syscall_arg__val(arg->args, idx);
1383}
David Ahern55d43bca2015-02-19 15:00:22 -05001384
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001385static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001386 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001387 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001388{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001389 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001390 unsigned long val;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001391
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001392 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001393 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001394 u8 bit = 1;
1395 struct syscall_arg arg = {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001396 .args = args,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001397 .idx = 0,
1398 .mask = 0,
1399 .trace = trace,
1400 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001401 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001402
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001403 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001404 field = field->next, ++arg.idx, bit <<= 1) {
1405 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001406 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001407
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001408 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001409
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001410 /*
1411 * Suppress this argument if its value is zero and
1412 * and we don't have a string associated in an
1413 * strarray for it.
1414 */
David Ahern55d43bca2015-02-19 15:00:22 -05001415 if (val == 0 &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001416 !(sc->arg_scnprintf &&
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -03001417 (sc->arg_scnprintf[arg.idx] == SCA_STRARRAY ||
1418 sc->arg_scnprintf[arg.idx] == SCA_STRARRAYS) &&
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001419 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001420 continue;
1421
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001422 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001423 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001424 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
David Ahern55d43bca2015-02-19 15:00:22 -05001425 arg.val = val;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001426 if (sc->arg_parm)
1427 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001428 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1429 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001430 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001431 printed += scnprintf(bf + printed, size - printed,
David Ahern55d43bca2015-02-19 15:00:22 -05001432 "%ld", val);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001433 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001434 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001435 } else if (IS_ERR(sc->tp_format)) {
1436 /*
1437 * If we managed to read the tracepoint /format file, then we
1438 * may end up not having any args, like with gettid(), so only
1439 * print the raw args when we didn't manage to read it.
1440 */
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001441 int i = 0;
1442
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001443 while (i < 6) {
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001444 val = __syscall_arg__val(args, i);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001445 printed += scnprintf(bf + printed, size - printed,
1446 "%sarg%d: %ld",
David Ahern55d43bca2015-02-19 15:00:22 -05001447 printed ? ", " : "", i, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001448 ++i;
1449 }
1450 }
1451
1452 return printed;
1453}
1454
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001455typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001456 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001457 struct perf_sample *sample);
1458
1459static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001460 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001461{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001462
1463 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001464
1465 /*
1466 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1467 * before that, leaving at a higher verbosity level till that is
1468 * explained. Reproduced with plain ftrace with:
1469 *
1470 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1471 * grep "NR -1 " /t/trace_pipe
1472 *
1473 * After generating some load on the machine.
1474 */
1475 if (verbose > 1) {
1476 static u64 n;
1477 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1478 id, perf_evsel__name(evsel), ++n);
1479 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001480 return NULL;
1481 }
1482
1483 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1484 trace__read_syscall_info(trace, id))
1485 goto out_cant_read;
1486
1487 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1488 goto out_cant_read;
1489
1490 return &trace->syscalls.table[id];
1491
1492out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001493 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001494 fprintf(trace->output, "Problems reading syscall %d", id);
1495 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1496 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1497 fputs(" information\n", trace->output);
1498 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001499 return NULL;
1500}
1501
David Ahernbf2575c2013-10-08 21:26:53 -06001502static void thread__update_stats(struct thread_trace *ttrace,
1503 int id, struct perf_sample *sample)
1504{
1505 struct int_node *inode;
1506 struct stats *stats;
1507 u64 duration = 0;
1508
1509 inode = intlist__findnew(ttrace->syscall_stats, id);
1510 if (inode == NULL)
1511 return;
1512
1513 stats = inode->priv;
1514 if (stats == NULL) {
1515 stats = malloc(sizeof(struct stats));
1516 if (stats == NULL)
1517 return;
1518 init_stats(stats);
1519 inode->priv = stats;
1520 }
1521
1522 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1523 duration = sample->time - ttrace->entry_time;
1524
1525 update_stats(stats, duration);
1526}
1527
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001528static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1529{
1530 struct thread_trace *ttrace;
1531 u64 duration;
1532 size_t printed;
1533
1534 if (trace->current == NULL)
1535 return 0;
1536
1537 ttrace = thread__priv(trace->current);
1538
1539 if (!ttrace->entry_pending)
1540 return 0;
1541
1542 duration = sample->time - ttrace->entry_time;
1543
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001544 printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001545 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1546 ttrace->entry_pending = false;
1547
1548 return printed;
1549}
1550
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001551static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001552 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001553 struct perf_sample *sample)
1554{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001555 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001556 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001557 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001558 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001559 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001560 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001561 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001562
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001563 if (sc == NULL)
1564 return -1;
1565
David Ahern8fb598e2013-09-28 13:13:00 -06001566 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001567 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001568 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001569 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001570
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001571 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001572
1573 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001574 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001575 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001576 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001577 }
1578
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001579 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo6ebad5c2015-03-25 18:01:15 -03001580 trace__printf_interrupted_entry(trace, sample);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001581
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001582 ttrace->entry_time = sample->time;
1583 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001584 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001585
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001586 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001587 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001588
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001589 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001590 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001591 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001592 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001593 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001594 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001595 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001596 /* See trace__vfs_getname & trace__sys_exit */
1597 ttrace->filename.pending_open = false;
1598 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001599
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001600 if (trace->current != thread) {
1601 thread__put(trace->current);
1602 trace->current = thread__get(thread);
1603 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001604 err = 0;
1605out_put:
1606 thread__put(thread);
1607 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001608}
1609
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001610static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1611 struct perf_sample *sample,
1612 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001613{
1614 struct addr_location al;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001615
1616 if (machine__resolve(trace->host, &al, sample) < 0 ||
1617 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack))
1618 return -1;
1619
1620 return 0;
1621}
1622
1623static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1624{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001625 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001626 const unsigned int print_opts = EVSEL__PRINT_SYM |
1627 EVSEL__PRINT_DSO |
1628 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001629
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001630 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001631}
1632
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001633static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001634 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001635 struct perf_sample *sample)
1636{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001637 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001638 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001639 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001640 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001641 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001642 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001643 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001644
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001645 if (sc == NULL)
1646 return -1;
1647
David Ahern8fb598e2013-09-28 13:13:00 -06001648 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001649 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001650 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001651 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001652
David Ahernbf2575c2013-10-08 21:26:53 -06001653 if (trace->summary)
1654 thread__update_stats(ttrace, id, sample);
1655
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001656 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001657
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001658 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001659 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1660 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001661 ++trace->stats.vfs_getname;
1662 }
1663
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001664 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001665 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001666 if (trace__filter_duration(trace, duration))
1667 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001668 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001669 } else if (trace->duration_filter)
1670 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001671
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001672 if (sample->callchain) {
1673 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1674 if (callchain_ret == 0) {
1675 if (callchain_cursor.nr < trace->min_stack)
1676 goto out;
1677 callchain_ret = 1;
1678 }
1679 }
1680
David Ahernfd2eaba2013-11-12 09:31:15 -07001681 if (trace->summary_only)
1682 goto out;
1683
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001684 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001685
1686 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001687 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001689 fprintf(trace->output, " ... [");
1690 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1691 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001692 }
1693
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001694 if (sc->fmt == NULL) {
1695signed_print:
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001696 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001697 } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001698 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001699 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001700 *e = audit_errno_to_name(-ret);
1701
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001702 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001703 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001704 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001705 else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001706 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001707 else if (sc->fmt->errpid) {
1708 struct thread *child = machine__find_thread(trace->host, ret, ret);
1709
1710 if (child != NULL) {
1711 fprintf(trace->output, ") = %ld", ret);
1712 if (child->comm_set)
1713 fprintf(trace->output, " (%s)", thread__comm_str(child));
1714 thread__put(child);
1715 }
1716 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001717 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001718
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001719 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001720
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001721 if (callchain_ret > 0)
1722 trace__fprintf_callchain(trace, sample);
1723 else if (callchain_ret < 0)
1724 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001725out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001726 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001727 err = 0;
1728out_put:
1729 thread__put(thread);
1730 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001731}
1732
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001733static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001734 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001735 struct perf_sample *sample)
1736{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001737 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1738 struct thread_trace *ttrace;
1739 size_t filename_len, entry_str_len, to_move;
1740 ssize_t remaining_space;
1741 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001742 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001743
1744 if (!thread)
1745 goto out;
1746
1747 ttrace = thread__priv(thread);
1748 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001749 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001750
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001751 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001752 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001753 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001754
1755 if (ttrace->filename.namelen < filename_len) {
1756 char *f = realloc(ttrace->filename.name, filename_len + 1);
1757
1758 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001759 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001760
1761 ttrace->filename.namelen = filename_len;
1762 ttrace->filename.name = f;
1763 }
1764
1765 strcpy(ttrace->filename.name, filename);
1766 ttrace->filename.pending_open = true;
1767
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001768 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001769 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001770
1771 entry_str_len = strlen(ttrace->entry_str);
1772 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1773 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001774 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001775
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001776 if (filename_len > (size_t)remaining_space) {
1777 filename += filename_len - remaining_space;
1778 filename_len = remaining_space;
1779 }
1780
1781 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1782 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1783 memmove(pos + filename_len, pos, to_move);
1784 memcpy(pos, filename, filename_len);
1785
1786 ttrace->filename.ptr = 0;
1787 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001788out_put:
1789 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001790out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001791 return 0;
1792}
1793
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001794static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001795 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001796 struct perf_sample *sample)
1797{
1798 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1799 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001800 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001801 sample->pid,
1802 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001803 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001804
1805 if (ttrace == NULL)
1806 goto out_dump;
1807
1808 ttrace->runtime_ms += runtime_ms;
1809 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001810out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001811 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001812 return 0;
1813
1814out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001815 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001816 evsel->name,
1817 perf_evsel__strval(evsel, sample, "comm"),
1818 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1819 runtime,
1820 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001821 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001822}
1823
Wang Nan1d6c9402016-02-26 09:31:55 +00001824static void bpf_output__printer(enum binary_printer_ops op,
1825 unsigned int val, void *extra)
1826{
1827 FILE *output = extra;
1828 unsigned char ch = (unsigned char)val;
1829
1830 switch (op) {
1831 case BINARY_PRINT_CHAR_DATA:
1832 fprintf(output, "%c", isprint(ch) ? ch : '.');
1833 break;
1834 case BINARY_PRINT_DATA_BEGIN:
1835 case BINARY_PRINT_LINE_BEGIN:
1836 case BINARY_PRINT_ADDR:
1837 case BINARY_PRINT_NUM_DATA:
1838 case BINARY_PRINT_NUM_PAD:
1839 case BINARY_PRINT_SEP:
1840 case BINARY_PRINT_CHAR_PAD:
1841 case BINARY_PRINT_LINE_END:
1842 case BINARY_PRINT_DATA_END:
1843 default:
1844 break;
1845 }
1846}
1847
1848static void bpf_output__fprintf(struct trace *trace,
1849 struct perf_sample *sample)
1850{
1851 print_binary(sample->raw_data, sample->raw_size, 8,
1852 bpf_output__printer, trace->output);
1853}
1854
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001855static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1856 union perf_event *event __maybe_unused,
1857 struct perf_sample *sample)
1858{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001859 int callchain_ret = 0;
1860
1861 if (sample->callchain) {
1862 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1863 if (callchain_ret == 0) {
1864 if (callchain_cursor.nr < trace->min_stack)
1865 goto out;
1866 callchain_ret = 1;
1867 }
1868 }
1869
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001870 trace__printf_interrupted_entry(trace, sample);
1871 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001872
1873 if (trace->trace_syscalls)
1874 fprintf(trace->output, "( ): ");
1875
1876 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001877
Wang Nan1d6c9402016-02-26 09:31:55 +00001878 if (perf_evsel__is_bpf_output(evsel)) {
1879 bpf_output__fprintf(trace, sample);
1880 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001881 event_format__fprintf(evsel->tp_format, sample->cpu,
1882 sample->raw_data, sample->raw_size,
1883 trace->output);
1884 }
1885
1886 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001887
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001888 if (callchain_ret > 0)
1889 trace__fprintf_callchain(trace, sample);
1890 else if (callchain_ret < 0)
1891 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1892out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001893 return 0;
1894}
1895
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001896static void print_location(FILE *f, struct perf_sample *sample,
1897 struct addr_location *al,
1898 bool print_dso, bool print_sym)
1899{
1900
Namhyung Kimbb963e12017-02-17 17:17:38 +09001901 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001902 fprintf(f, "%s@", al->map->dso->long_name);
1903
Namhyung Kimbb963e12017-02-17 17:17:38 +09001904 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001905 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001906 al->addr - al->sym->start);
1907 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001908 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001909 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001910 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001911}
1912
1913static int trace__pgfault(struct trace *trace,
1914 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001915 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001916 struct perf_sample *sample)
1917{
1918 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001919 struct addr_location al;
1920 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001921 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001922 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001923 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001924
1925 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001926
1927 if (sample->callchain) {
1928 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1929 if (callchain_ret == 0) {
1930 if (callchain_cursor.nr < trace->min_stack)
1931 goto out_put;
1932 callchain_ret = 1;
1933 }
1934 }
1935
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001936 ttrace = thread__trace(thread, trace->output);
1937 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001938 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001939
1940 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
1941 ttrace->pfmaj++;
1942 else
1943 ttrace->pfmin++;
1944
1945 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001946 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001947
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001948 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001949 sample->ip, &al);
1950
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001951 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001952
1953 fprintf(trace->output, "%sfault [",
1954 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
1955 "maj" : "min");
1956
1957 print_location(trace->output, sample, &al, false, true);
1958
1959 fprintf(trace->output, "] => ");
1960
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001961 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001962 sample->addr, &al);
1963
1964 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001965 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001966 MAP__FUNCTION, sample->addr, &al);
1967
1968 if (al.map)
1969 map_type = 'x';
1970 else
1971 map_type = '?';
1972 }
1973
1974 print_location(trace->output, sample, &al, true, false);
1975
1976 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03001977
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001978 if (callchain_ret > 0)
1979 trace__fprintf_callchain(trace, sample);
1980 else if (callchain_ret < 0)
1981 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001982out:
1983 err = 0;
1984out_put:
1985 thread__put(thread);
1986 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001987}
1988
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001989static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001990 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03001991 struct perf_sample *sample)
1992{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03001993 /*
1994 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
1995 * and don't use sample->time unconditionally, we may end up having
1996 * some other event in the future without PERF_SAMPLE_TIME for good
1997 * reason, i.e. we may not be interested in its timestamps, just in
1998 * it taking place, picking some piece of information when it
1999 * appears in our event stream (vfs_getname comes to mind).
2000 */
2001 if (trace->base_time == 0 && !trace->full_time &&
2002 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002003 trace->base_time = sample->time;
2004}
2005
David Ahern6810fc92013-08-28 22:29:52 -06002006static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002007 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002008 struct perf_sample *sample,
2009 struct perf_evsel *evsel,
2010 struct machine *machine __maybe_unused)
2011{
2012 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002013 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002014 int err = 0;
2015
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002016 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002017
David Ahernaa07df62016-11-25 09:29:52 -07002018 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2019 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002020 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002021
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002022 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002023
David Ahern31605652013-12-04 19:41:41 -07002024 if (handler) {
2025 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002026 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002027 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002028out:
2029 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002030 return err;
2031}
2032
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002033static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002034{
2035 unsigned int rec_argc, i, j;
2036 const char **rec_argv;
2037 const char * const record_args[] = {
2038 "record",
2039 "-R",
2040 "-m", "1024",
2041 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002042 };
2043
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002044 const char * const sc_args[] = { "-e", };
2045 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2046 const char * const majpf_args[] = { "-e", "major-faults" };
2047 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2048 const char * const minpf_args[] = { "-e", "minor-faults" };
2049 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2050
David Ahern9aca7f12013-12-04 19:41:39 -07002051 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002052 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2053 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002054 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2055
2056 if (rec_argv == NULL)
2057 return -ENOMEM;
2058
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002059 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002060 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002061 rec_argv[j++] = record_args[i];
2062
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002063 if (trace->trace_syscalls) {
2064 for (i = 0; i < sc_args_nr; i++)
2065 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002066
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002067 /* event string may be different for older kernels - e.g., RHEL6 */
2068 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2069 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2070 else if (is_valid_tracepoint("syscalls:sys_enter"))
2071 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2072 else {
2073 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2074 return -1;
2075 }
David Ahern9aca7f12013-12-04 19:41:39 -07002076 }
David Ahern9aca7f12013-12-04 19:41:39 -07002077
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002078 if (trace->trace_pgfaults & TRACE_PFMAJ)
2079 for (i = 0; i < majpf_args_nr; i++)
2080 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002081
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002082 if (trace->trace_pgfaults & TRACE_PFMIN)
2083 for (i = 0; i < minpf_args_nr; i++)
2084 rec_argv[j++] = minpf_args[i];
2085
2086 for (i = 0; i < (unsigned int)argc; i++)
2087 rec_argv[j++] = argv[i];
2088
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002089 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002090}
2091
David Ahernbf2575c2013-10-08 21:26:53 -06002092static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2093
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002094static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002095{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002096 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002097
2098 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002099 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002100
2101 if (perf_evsel__field(evsel, "pathname") == NULL) {
2102 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002103 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002104 }
2105
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002106 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002107 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002108 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002109}
2110
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002111static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002112{
2113 struct perf_evsel *evsel;
2114 struct perf_event_attr attr = {
2115 .type = PERF_TYPE_SOFTWARE,
2116 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002117 };
2118
2119 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002120 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002121
2122 event_attr_init(&attr);
2123
2124 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002125 if (evsel)
2126 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002127
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002128 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002129}
2130
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002131static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2132{
2133 const u32 type = event->header.type;
2134 struct perf_evsel *evsel;
2135
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002136 if (type != PERF_RECORD_SAMPLE) {
2137 trace__process_event(trace, trace->host, event, sample);
2138 return;
2139 }
2140
2141 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2142 if (evsel == NULL) {
2143 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2144 return;
2145 }
2146
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002147 trace__set_base_time(trace, evsel, sample);
2148
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002149 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2150 sample->raw_data == NULL) {
2151 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2152 perf_evsel__name(evsel), sample->tid,
2153 sample->cpu, sample->raw_size);
2154 } else {
2155 tracepoint_handler handler = evsel->handler;
2156 handler(trace, evsel, event, sample);
2157 }
2158}
2159
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002160static int trace__add_syscall_newtp(struct trace *trace)
2161{
2162 int ret = -1;
2163 struct perf_evlist *evlist = trace->evlist;
2164 struct perf_evsel *sys_enter, *sys_exit;
2165
2166 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2167 if (sys_enter == NULL)
2168 goto out;
2169
2170 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2171 goto out_delete_sys_enter;
2172
2173 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2174 if (sys_exit == NULL)
2175 goto out_delete_sys_enter;
2176
2177 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2178 goto out_delete_sys_exit;
2179
2180 perf_evlist__add(evlist, sys_enter);
2181 perf_evlist__add(evlist, sys_exit);
2182
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002183 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002184 /*
2185 * We're interested only in the user space callchain
2186 * leading to the syscall, allow overriding that for
2187 * debugging reasons using --kernel_syscall_callchains
2188 */
2189 sys_exit->attr.exclude_callchain_kernel = 1;
2190 }
2191
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002192 trace->syscalls.events.sys_enter = sys_enter;
2193 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002194
2195 ret = 0;
2196out:
2197 return ret;
2198
2199out_delete_sys_exit:
2200 perf_evsel__delete_priv(sys_exit);
2201out_delete_sys_enter:
2202 perf_evsel__delete_priv(sys_enter);
2203 goto out;
2204}
2205
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002206static int trace__set_ev_qualifier_filter(struct trace *trace)
2207{
2208 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002209 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002210 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2211 trace->ev_qualifier_ids.nr,
2212 trace->ev_qualifier_ids.entries);
2213
2214 if (filter == NULL)
2215 goto out_enomem;
2216
Mathieu Poirier3541c032016-09-16 08:44:04 -06002217 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2218 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002219 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002220 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002221 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002222
2223 free(filter);
2224out:
2225 return err;
2226out_enomem:
2227 errno = ENOMEM;
2228 goto out;
2229}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002230
Namhyung Kimf15eb532012-10-05 14:02:16 +09002231static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002232{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002233 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002234 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002235 int err = -1, i;
2236 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002237 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002238 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002239
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002240 trace->live = true;
2241
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002242 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002243 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002244
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002245 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002246 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002247
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002248 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2249 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2250 if (pgfault_maj == NULL)
2251 goto out_error_mem;
2252 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002253 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002254
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002255 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2256 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2257 if (pgfault_min == NULL)
2258 goto out_error_mem;
2259 perf_evlist__add(evlist, pgfault_min);
2260 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002261
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002262 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002263 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2264 trace__sched_stat_runtime))
2265 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002266
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002267 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2268 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002269 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002270 goto out_delete_evlist;
2271 }
2272
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002273 err = trace__symbols_init(trace, evlist);
2274 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002275 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002276 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002277 }
2278
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002279 perf_evlist__config(evlist, &trace->opts, NULL);
2280
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002281 if (callchain_param.enabled) {
2282 bool use_identifier = false;
2283
2284 if (trace->syscalls.events.sys_exit) {
2285 perf_evsel__config_callchain(trace->syscalls.events.sys_exit,
2286 &trace->opts, &callchain_param);
2287 use_identifier = true;
2288 }
2289
2290 if (pgfault_maj) {
2291 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
2292 use_identifier = true;
2293 }
2294
2295 if (pgfault_min) {
2296 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
2297 use_identifier = true;
2298 }
2299
2300 if (use_identifier) {
2301 /*
2302 * Now we have evsels with different sample_ids, use
2303 * PERF_SAMPLE_IDENTIFIER to map from sample to evsel
2304 * from a fixed position in each ring buffer record.
2305 *
2306 * As of this the changeset introducing this comment, this
2307 * isn't strictly needed, as the fields that can come before
2308 * PERF_SAMPLE_ID are all used, but we'll probably disable
2309 * some of those for things like copying the payload of
2310 * pointer syscall arguments, and for vfs_getname we don't
2311 * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this
2312 * here as a warning we need to use PERF_SAMPLE_IDENTIFIER.
2313 */
2314 perf_evlist__set_sample_bit(evlist, IDENTIFIER);
2315 perf_evlist__reset_sample_bit(evlist, ID);
2316 }
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002317 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002318
Namhyung Kimf15eb532012-10-05 14:02:16 +09002319 signal(SIGCHLD, sig_handler);
2320 signal(SIGINT, sig_handler);
2321
2322 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002323 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002324 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002325 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002326 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002327 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002328 }
2329 }
2330
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002331 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002332 if (err < 0)
2333 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002334
Wang Nanba504232016-02-26 09:31:54 +00002335 err = bpf__apply_obj_config();
2336 if (err) {
2337 char errbuf[BUFSIZ];
2338
2339 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2340 pr_err("ERROR: Apply config to BPF failed: %s\n",
2341 errbuf);
2342 goto out_error_open;
2343 }
2344
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002345 /*
2346 * Better not use !target__has_task() here because we need to cover the
2347 * case where no threads were specified in the command line, but a
2348 * workload was, and in that case we will fill in the thread_map when
2349 * we fork the workload in perf_evlist__prepare_workload.
2350 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002351 if (trace->filter_pids.nr > 0)
2352 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002353 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002354 err = perf_evlist__set_filter_pid(evlist, getpid());
2355
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002356 if (err < 0)
2357 goto out_error_mem;
2358
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002359 if (trace->ev_qualifier_ids.nr > 0) {
2360 err = trace__set_ev_qualifier_filter(trace);
2361 if (err < 0)
2362 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002363
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002364 pr_debug("event qualifier tracepoint filter: %s\n",
2365 trace->syscalls.events.sys_exit->filter);
2366 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002367
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002368 err = perf_evlist__apply_filters(evlist, &evsel);
2369 if (err < 0)
2370 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002371
Jiri Olsaf8850372013-11-28 17:57:22 +01002372 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002373 if (err < 0)
2374 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002375
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002376 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002377 perf_evlist__enable(evlist);
2378
Namhyung Kimf15eb532012-10-05 14:02:16 +09002379 if (forks)
2380 perf_evlist__start_workload(evlist);
2381
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002382 if (trace->opts.initial_delay) {
2383 usleep(trace->opts.initial_delay * 1000);
2384 perf_evlist__enable(evlist);
2385 }
2386
Jiri Olsae13798c2015-06-23 00:36:02 +02002387 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002388 evlist->threads->nr > 1 ||
2389 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002390again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002391 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392
2393 for (i = 0; i < evlist->nr_mmaps; i++) {
2394 union perf_event *event;
2395
2396 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002397 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002398
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002399 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002400
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002401 err = perf_evlist__parse_sample(evlist, event, &sample);
2402 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002403 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002404 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002405 }
2406
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002407 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002408next_event:
2409 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002410
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002411 if (interrupted)
2412 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002413
2414 if (done && !draining) {
2415 perf_evlist__disable(evlist);
2416 draining = true;
2417 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002418 }
2419 }
2420
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002421 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002422 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002423
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002424 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2425 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2426 draining = true;
2427
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002428 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002429 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002430 } else {
2431 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002432 }
2433
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002434out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002435 thread__zput(trace->current);
2436
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002437 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002438
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002439 if (!err) {
2440 if (trace->summary)
2441 trace__fprintf_thread_summary(trace, trace->output);
2442
2443 if (trace->show_tool_stats) {
2444 fprintf(trace->output, "Stats:\n "
2445 " vfs_getname : %" PRIu64 "\n"
2446 " proc_getname: %" PRIu64 "\n",
2447 trace->stats.vfs_getname,
2448 trace->stats.proc_getname);
2449 }
2450 }
David Ahernbf2575c2013-10-08 21:26:53 -06002451
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002452out_delete_evlist:
2453 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002454 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002455 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002456 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002457{
2458 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002459
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002460out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002461 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002462 goto out_error;
2463
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002464out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002465 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002466 goto out_error;
2467
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002468out_error_mmap:
2469 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2470 goto out_error;
2471
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002472out_error_open:
2473 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2474
2475out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002476 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302477 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002478
2479out_error_apply_filters:
2480 fprintf(trace->output,
2481 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2482 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002483 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002484 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002485}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002486out_error_mem:
2487 fprintf(trace->output, "Not enough memory to run!\n");
2488 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002489
2490out_errno:
2491 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2492 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002493}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002494
David Ahern6810fc92013-08-28 22:29:52 -06002495static int trace__replay(struct trace *trace)
2496{
2497 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002498 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002499 };
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002500 struct perf_data_file file = {
2501 .path = input_name,
2502 .mode = PERF_DATA_MODE_READ,
Yunlong Songe366a6d2015-04-02 21:47:18 +08002503 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002504 };
David Ahern6810fc92013-08-28 22:29:52 -06002505 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002506 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002507 int err = -1;
2508
2509 trace->tool.sample = trace__process_sample;
2510 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002511 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002512 trace->tool.comm = perf_event__process_comm;
2513 trace->tool.exit = perf_event__process_exit;
2514 trace->tool.fork = perf_event__process_fork;
2515 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302516 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002517 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302518 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002519
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002520 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002521 trace->tool.ordering_requires_timestamps = true;
2522
2523 /* add tid to output */
2524 trace->multiple_threads = true;
2525
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002526 session = perf_session__new(&file, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002527 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002528 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002529
David Ahernaa07df62016-11-25 09:29:52 -07002530 if (trace->opts.target.pid)
2531 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2532
2533 if (trace->opts.target.tid)
2534 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2535
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002536 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002537 goto out;
2538
David Ahern8fb598e2013-09-28 13:13:00 -06002539 trace->host = &session->machines.host;
2540
David Ahern6810fc92013-08-28 22:29:52 -06002541 err = perf_session__set_tracepoints_handlers(session, handlers);
2542 if (err)
2543 goto out;
2544
Namhyung Kim003824e2013-11-12 15:25:00 +09002545 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2546 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002547 /* older kernels have syscalls tp versus raw_syscalls */
2548 if (evsel == NULL)
2549 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2550 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002551
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002552 if (evsel &&
2553 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2554 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002555 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2556 goto out;
2557 }
2558
2559 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2560 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002561 if (evsel == NULL)
2562 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2563 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002564 if (evsel &&
2565 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2566 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002567 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002568 goto out;
2569 }
2570
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002571 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002572 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2573 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2574 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2575 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2576 evsel->handler = trace__pgfault;
2577 }
2578
David Ahern6810fc92013-08-28 22:29:52 -06002579 setup_pager();
2580
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002581 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002582 if (err)
2583 pr_err("Failed to process events, error %d", err);
2584
David Ahernbf2575c2013-10-08 21:26:53 -06002585 else if (trace->summary)
2586 trace__fprintf_thread_summary(trace, trace->output);
2587
David Ahern6810fc92013-08-28 22:29:52 -06002588out:
2589 perf_session__delete(session);
2590
2591 return err;
2592}
2593
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002594static size_t trace__fprintf_threads_header(FILE *fp)
2595{
2596 size_t printed;
2597
Pekka Enberg99ff7152013-11-12 16:42:14 +02002598 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002599
2600 return printed;
2601}
2602
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002603DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2604 struct stats *stats;
2605 double msecs;
2606 int syscall;
2607)
2608{
2609 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2610 struct stats *stats = source->priv;
2611
2612 entry->syscall = source->i;
2613 entry->stats = stats;
2614 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2615}
2616
David Ahernbf2575c2013-10-08 21:26:53 -06002617static size_t thread__dump_stats(struct thread_trace *ttrace,
2618 struct trace *trace, FILE *fp)
2619{
David Ahernbf2575c2013-10-08 21:26:53 -06002620 size_t printed = 0;
2621 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002622 struct rb_node *nd;
2623 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002624
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002625 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002626 return 0;
2627
2628 printed += fprintf(fp, "\n");
2629
Milian Wolff834fd462015-08-06 11:24:29 +02002630 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2631 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2632 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002633
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002634 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002635 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002636 if (stats) {
2637 double min = (double)(stats->min) / NSEC_PER_MSEC;
2638 double max = (double)(stats->max) / NSEC_PER_MSEC;
2639 double avg = avg_stats(stats);
2640 double pct;
2641 u64 n = (u64) stats->n;
2642
2643 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2644 avg /= NSEC_PER_MSEC;
2645
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002646 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002647 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002648 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002649 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002650 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002651 }
David Ahernbf2575c2013-10-08 21:26:53 -06002652 }
2653
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002654 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002655 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002656
2657 return printed;
2658}
2659
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002660static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002661{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002662 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002663 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002664 double ratio;
2665
2666 if (ttrace == NULL)
2667 return 0;
2668
2669 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2670
Pekka Enberg15e65c62013-11-14 18:43:30 +02002671 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002672 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002673 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002674 if (ttrace->pfmaj)
2675 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2676 if (ttrace->pfmin)
2677 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002678 if (trace->sched)
2679 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2680 else if (fputc('\n', fp) != EOF)
2681 ++printed;
2682
David Ahernbf2575c2013-10-08 21:26:53 -06002683 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002684
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002685 return printed;
2686}
David Ahern896cbb52013-09-28 13:12:59 -06002687
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002688static unsigned long thread__nr_events(struct thread_trace *ttrace)
2689{
2690 return ttrace ? ttrace->nr_events : 0;
2691}
2692
2693DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2694 struct thread *thread;
2695)
2696{
2697 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002698}
2699
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002700static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2701{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002702 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host);
2703 size_t printed = trace__fprintf_threads_header(fp);
2704 struct rb_node *nd;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002705
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002706 if (threads == NULL) {
2707 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2708 return 0;
2709 }
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002710
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002711 resort_rb__for_each_entry(nd, threads)
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002712 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2713
2714 resort_rb__delete(threads);
2715
2716 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002717}
2718
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002719static int trace__set_duration(const struct option *opt, const char *str,
2720 int unset __maybe_unused)
2721{
2722 struct trace *trace = opt->value;
2723
2724 trace->duration_filter = atof(str);
2725 return 0;
2726}
2727
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002728static int trace__set_filter_pids(const struct option *opt, const char *str,
2729 int unset __maybe_unused)
2730{
2731 int ret = -1;
2732 size_t i;
2733 struct trace *trace = opt->value;
2734 /*
2735 * FIXME: introduce a intarray class, plain parse csv and create a
2736 * { int nr, int entries[] } struct...
2737 */
2738 struct intlist *list = intlist__new(str);
2739
2740 if (list == NULL)
2741 return -1;
2742
2743 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2744 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2745
2746 if (trace->filter_pids.entries == NULL)
2747 goto out;
2748
2749 trace->filter_pids.entries[0] = getpid();
2750
2751 for (i = 1; i < trace->filter_pids.nr; ++i)
2752 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2753
2754 intlist__delete(list);
2755 ret = 0;
2756out:
2757 return ret;
2758}
2759
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002760static int trace__open_output(struct trace *trace, const char *filename)
2761{
2762 struct stat st;
2763
2764 if (!stat(filename, &st) && st.st_size) {
2765 char oldname[PATH_MAX];
2766
2767 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2768 unlink(oldname);
2769 rename(filename, oldname);
2770 }
2771
2772 trace->output = fopen(filename, "w");
2773
2774 return trace->output == NULL ? -errno : 0;
2775}
2776
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002777static int parse_pagefaults(const struct option *opt, const char *str,
2778 int unset __maybe_unused)
2779{
2780 int *trace_pgfaults = opt->value;
2781
2782 if (strcmp(str, "all") == 0)
2783 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2784 else if (strcmp(str, "maj") == 0)
2785 *trace_pgfaults |= TRACE_PFMAJ;
2786 else if (strcmp(str, "min") == 0)
2787 *trace_pgfaults |= TRACE_PFMIN;
2788 else
2789 return -1;
2790
2791 return 0;
2792}
2793
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002794static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2795{
2796 struct perf_evsel *evsel;
2797
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002798 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002799 evsel->handler = handler;
2800}
2801
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002802/*
2803 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2804 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2805 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2806 *
2807 * It'd be better to introduce a parse_options() variant that would return a
2808 * list with the terms it didn't match to an event...
2809 */
2810static int trace__parse_events_option(const struct option *opt, const char *str,
2811 int unset __maybe_unused)
2812{
2813 struct trace *trace = (struct trace *)opt->value;
2814 const char *s = str;
2815 char *sep = NULL, *lists[2] = { NULL, NULL, };
2816 int len = strlen(str), err = -1, list;
2817 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2818 char group_name[PATH_MAX];
2819
2820 if (strace_groups_dir == NULL)
2821 return -1;
2822
2823 if (*s == '!') {
2824 ++s;
2825 trace->not_ev_qualifier = true;
2826 }
2827
2828 while (1) {
2829 if ((sep = strchr(s, ',')) != NULL)
2830 *sep = '\0';
2831
2832 list = 0;
2833 if (syscalltbl__id(trace->sctbl, s) >= 0) {
2834 list = 1;
2835 } else {
2836 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2837 if (access(group_name, R_OK) == 0)
2838 list = 1;
2839 }
2840
2841 if (lists[list]) {
2842 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2843 } else {
2844 lists[list] = malloc(len);
2845 if (lists[list] == NULL)
2846 goto out;
2847 strcpy(lists[list], s);
2848 }
2849
2850 if (!sep)
2851 break;
2852
2853 *sep = ',';
2854 s = sep + 1;
2855 }
2856
2857 if (lists[1] != NULL) {
2858 struct strlist_config slist_config = {
2859 .dirname = strace_groups_dir,
2860 };
2861
2862 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2863 if (trace->ev_qualifier == NULL) {
2864 fputs("Not enough memory to parse event qualifier", trace->output);
2865 goto out;
2866 }
2867
2868 if (trace__validate_ev_qualifier(trace))
2869 goto out;
2870 }
2871
2872 err = 0;
2873
2874 if (lists[0]) {
2875 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2876 "event selector. use 'perf list' to list available events",
2877 parse_events_option);
2878 err = parse_events_option(&o, lists[0], 0);
2879 }
2880out:
2881 if (sep)
2882 *sep = ',';
2883
2884 return err;
2885}
2886
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002887int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002888{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002889 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002890 "perf trace [<options>] [<command>]",
2891 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002892 "perf trace record [<options>] [<command>]",
2893 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002894 NULL
2895 };
2896 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002897 .syscalls = {
2898 . max = -1,
2899 },
2900 .opts = {
2901 .target = {
2902 .uid = UINT_MAX,
2903 .uses_mmap = true,
2904 },
2905 .user_freq = UINT_MAX,
2906 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002907 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002908 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002909 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002910 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002911 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002912 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002913 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002914 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03002915 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002916 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002917 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002918 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002919 OPT_CALLBACK('e', "event", &trace, "event",
2920 "event/syscall selector. use 'perf list' to list available events",
2921 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002922 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2923 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002924 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002925 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
2926 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002927 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06002928 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002929 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2930 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06002931 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002932 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03002933 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2934 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06002935 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002936 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06002937 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002938 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06002939 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002940 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02002941 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2942 "number of mmap data pages",
2943 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06002944 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002945 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002946 OPT_CALLBACK(0, "duration", &trace, "float",
2947 "show only events with duration > N.M ms",
2948 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002949 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03002950 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06002951 OPT_BOOLEAN('T', "time", &trace.full_time,
2952 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07002953 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2954 "Show only syscall summary with statistics"),
2955 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2956 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002957 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2958 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002959 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08002960 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02002961 OPT_CALLBACK(0, "call-graph", &trace.opts,
2962 "record_mode[,record_size]", record_callchain_help,
2963 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002964 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
2965 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03002966 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
2967 "Set the minimum stack depth when parsing the callchain, "
2968 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03002969 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
2970 "Set the maximum stack depth when parsing the callchain, "
2971 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03002972 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Kan Liang9d9cad72015-06-17 09:51:11 -04002973 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2974 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002975 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
2976 "ms to wait before starting measurement after program "
2977 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002978 OPT_END()
2979 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03002980 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03002981 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002982 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002983 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09002984 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002985
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03002986 signal(SIGSEGV, sighandler_dump_stack);
2987 signal(SIGFPE, sighandler_dump_stack);
2988
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002989 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002990 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002991
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03002992 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002993 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00002994 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002995 goto out;
2996 }
2997
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002998 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2999 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003000
Wang Nand7888572016-04-08 15:07:24 +00003001 err = bpf__setup_stdout(trace.evlist);
3002 if (err) {
3003 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3004 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3005 goto out;
3006 }
3007
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003008 err = -1;
3009
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003010 if (trace.trace_pgfaults) {
3011 trace.opts.sample_address = true;
3012 trace.opts.sample_time = true;
3013 }
3014
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003015 if (trace.opts.mmap_pages == UINT_MAX)
3016 mmap_pages_user_set = false;
3017
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003018 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003019 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003020 max_stack_user_set = false;
3021 }
3022
3023#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melocaa36ed2016-05-19 19:00:27 -03003024 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled && trace.trace_syscalls)
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003025 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
3026#endif
3027
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003028 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003029 if (!mmap_pages_user_set && geteuid() == 0)
3030 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3031
Milian Wolff566a0882016-04-08 13:34:15 +02003032 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003033 }
Milian Wolff566a0882016-04-08 13:34:15 +02003034
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003035 if (trace.evlist->nr_entries > 0)
3036 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3037
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003038 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3039 return trace__record(&trace, argc-1, &argv[1]);
3040
3041 /* summary_only implies summary option, but don't overwrite summary if set */
3042 if (trace.summary_only)
3043 trace.summary = trace.summary_only;
3044
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003045 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3046 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003047 pr_err("Please specify something to trace.\n");
3048 return -1;
3049 }
3050
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003051 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003052 pr_err("The -e option can't be used with --no-syscalls.\n");
3053 goto out;
3054 }
3055
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003056 if (output_name != NULL) {
3057 err = trace__open_output(&trace, output_name);
3058 if (err < 0) {
3059 perror("failed to create output file");
3060 goto out;
3061 }
3062 }
3063
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003064 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3065
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003066 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003067 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003068 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003069 fprintf(trace.output, "%s", bf);
3070 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003071 }
3072
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003073 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003074 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003075 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003076 fprintf(trace.output, "%s", bf);
3077 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003078 }
3079
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003080 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003081 trace.opts.target.system_wide = true;
3082
David Ahern6810fc92013-08-28 22:29:52 -06003083 if (input_name)
3084 err = trace__replay(&trace);
3085 else
3086 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003087
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003088out_close:
3089 if (output_name != NULL)
3090 fclose(trace.output);
3091out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003092 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003093}