blob: 7fca844ced0b2e4ed997b0f7ad69db2f7510420b [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 Melo9ea42ba2018-03-06 16:30:51 -030022#include "util/cgroup.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030023#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030024#include "util/debug.h"
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +010025#include "util/env.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030026#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030027#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060028#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030029#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030030#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060031#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030032#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060033#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030034#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060035#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030036#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060037#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030038#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010039#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070040#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000041#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020042#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030043#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030044#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030045#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030046#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030047
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030048#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030049#include <inttypes.h>
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030050#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030051#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030052#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030053#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020054#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030055#include <linux/filter.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 Melobafae982018-01-22 16:42:16 -030060#include <fcntl.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030061
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030062#include "sane_ctype.h"
63
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030064#ifndef O_CLOEXEC
65# define O_CLOEXEC 02000000
66#endif
67
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030068#ifndef F_LINUX_SPECIFIC_BASE
69# define F_LINUX_SPECIFIC_BASE 1024
70#endif
71
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030072struct trace {
73 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030074 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030075 struct {
76 int max;
77 struct syscall *table;
78 struct {
79 struct perf_evsel *sys_enter,
80 *sys_exit;
81 } events;
82 } syscalls;
83 struct record_opts opts;
84 struct perf_evlist *evlist;
85 struct machine *host;
86 struct thread *current;
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -030087 struct cgroup *cgroup;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030088 u64 base_time;
89 FILE *output;
90 unsigned long nr_events;
91 struct strlist *ev_qualifier;
92 struct {
93 size_t nr;
94 int *entries;
95 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030096 struct {
97 size_t nr;
98 pid_t *entries;
99 } filter_pids;
100 double duration_filter;
101 double runtime_ms;
102 struct {
103 u64 vfs_getname,
104 proc_getname;
105 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300106 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300107 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300108 bool not_ev_qualifier;
109 bool live;
110 bool full_time;
111 bool sched;
112 bool multiple_threads;
113 bool summary;
114 bool summary_only;
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -0300115 bool failure_only;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300116 bool show_comm;
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -0300117 bool print_sample;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300118 bool show_tool_stats;
119 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300120 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121 bool force;
122 bool vfs_getname;
123 int trace_pgfaults;
124};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300125
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300126struct tp_field {
127 int offset;
128 union {
129 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
130 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
131 };
132};
133
134#define TP_UINT_FIELD(bits) \
135static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
136{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500137 u##bits value; \
138 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
139 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300140}
141
142TP_UINT_FIELD(8);
143TP_UINT_FIELD(16);
144TP_UINT_FIELD(32);
145TP_UINT_FIELD(64);
146
147#define TP_UINT_FIELD__SWAPPED(bits) \
148static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
149{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500150 u##bits value; \
151 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300152 return bswap_##bits(value);\
153}
154
155TP_UINT_FIELD__SWAPPED(16);
156TP_UINT_FIELD__SWAPPED(32);
157TP_UINT_FIELD__SWAPPED(64);
158
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300159static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300160{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300161 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300162
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300163 switch (size) {
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300164 case 1:
165 field->integer = tp_field__u8;
166 break;
167 case 2:
168 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
169 break;
170 case 4:
171 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
172 break;
173 case 8:
174 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
175 break;
176 default:
177 return -1;
178 }
179
180 return 0;
181}
182
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300183static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap)
184{
185 return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
186}
187
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300188static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
189{
190 return sample->raw_data + field->offset;
191}
192
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300193static int __tp_field__init_ptr(struct tp_field *field, int offset)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300194{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300195 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300196 field->pointer = tp_field__ptr;
197 return 0;
198}
199
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300200static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
201{
202 return __tp_field__init_ptr(field, format_field->offset);
203}
204
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300205struct syscall_tp {
206 struct tp_field id;
207 union {
208 struct tp_field args, ret;
209 };
210};
211
212static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
213 struct tp_field *field,
214 const char *name)
215{
216 struct format_field *format_field = perf_evsel__field(evsel, name);
217
218 if (format_field == NULL)
219 return -1;
220
221 return tp_field__init_uint(field, format_field, evsel->needs_swap);
222}
223
224#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
225 ({ struct syscall_tp *sc = evsel->priv;\
226 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
227
228static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
229 struct tp_field *field,
230 const char *name)
231{
232 struct format_field *format_field = perf_evsel__field(evsel, name);
233
234 if (format_field == NULL)
235 return -1;
236
237 return tp_field__init_ptr(field, format_field);
238}
239
240#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
241 ({ struct syscall_tp *sc = evsel->priv;\
242 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
243
244static void perf_evsel__delete_priv(struct perf_evsel *evsel)
245{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300246 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300247 perf_evsel__delete(evsel);
248}
249
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300250static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler)
Namhyung Kim96695d42013-11-12 08:51:45 -0300251{
252 evsel->priv = malloc(sizeof(struct syscall_tp));
253 if (evsel->priv != NULL) {
254 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
255 goto out_delete;
256
257 evsel->handler = handler;
258 return 0;
259 }
260
261 return -ENOMEM;
262
263out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300264 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300265 return -ENOENT;
266}
267
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300268static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300269{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300270 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300271
David Ahern9aca7f12013-12-04 19:41:39 -0700272 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200273 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700274 evsel = perf_evsel__newtp("syscalls", direction);
275
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200276 if (IS_ERR(evsel))
277 return NULL;
278
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300279 if (perf_evsel__init_raw_syscall_tp(evsel, handler))
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200280 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300281
282 return evsel;
283
284out_delete:
285 perf_evsel__delete_priv(evsel);
286 return NULL;
287}
288
289#define perf_evsel__sc_tp_uint(evsel, name, sample) \
290 ({ struct syscall_tp *fields = evsel->priv; \
291 fields->name.integer(&fields->name, sample); })
292
293#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
294 ({ struct syscall_tp *fields = evsel->priv; \
295 fields->name.pointer(&fields->name, sample); })
296
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300297size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
298{
299 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300
Arnaldo Carvalho de Melobc972ad2018-07-26 15:30:33 -0300301 if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL)
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300302 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300303
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300304 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300305}
306
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300307static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
308 const char *intfmt,
309 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300310{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300311 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300312}
313
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300314static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
315 struct syscall_arg *arg)
316{
317 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
318}
319
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300320#define SCA_STRARRAY syscall_arg__scnprintf_strarray
321
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300322struct strarrays {
323 int nr_entries;
324 struct strarray **entries;
325};
326
327#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
328 .nr_entries = ARRAY_SIZE(array), \
329 .entries = array, \
330}
331
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300332size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
333 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300334{
335 struct strarrays *sas = arg->parm;
336 int i;
337
338 for (i = 0; i < sas->nr_entries; ++i) {
339 struct strarray *sa = sas->entries[i];
340 int idx = arg->val - sa->offset;
341
342 if (idx >= 0 && idx < sa->nr_entries) {
343 if (sa->entries[idx] == NULL)
344 break;
345 return scnprintf(bf, size, "%s", sa->entries[idx]);
346 }
347 }
348
349 return scnprintf(bf, size, "%d", arg->val);
350}
351
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300352#ifndef AT_FDCWD
353#define AT_FDCWD -100
354#endif
355
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300356static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
357 struct syscall_arg *arg)
358{
359 int fd = arg->val;
360
361 if (fd == AT_FDCWD)
362 return scnprintf(bf, size, "CWD");
363
364 return syscall_arg__scnprintf_fd(bf, size, arg);
365}
366
367#define SCA_FDAT syscall_arg__scnprintf_fd_at
368
369static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
370 struct syscall_arg *arg);
371
372#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
373
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300374size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300375{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300376 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300377}
378
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300379size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300380{
381 return scnprintf(bf, size, "%d", arg->val);
382}
383
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300384size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
385{
386 return scnprintf(bf, size, "%ld", arg->val);
387}
388
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300389static const char *bpf_cmd[] = {
390 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
391 "MAP_GET_NEXT_KEY", "PROG_LOAD",
392};
393static DEFINE_STRARRAY(bpf_cmd);
394
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300395static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
396static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300397
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300398static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
399static DEFINE_STRARRAY(itimers);
400
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300401static const char *keyctl_options[] = {
402 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
403 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
404 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
405 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
406 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
407};
408static DEFINE_STRARRAY(keyctl_options);
409
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300410static const char *whences[] = { "SET", "CUR", "END",
411#ifdef SEEK_DATA
412"DATA",
413#endif
414#ifdef SEEK_HOLE
415"HOLE",
416#endif
417};
418static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300419
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300420static const char *fcntl_cmds[] = {
421 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300422 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
423 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
424 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300425};
426static DEFINE_STRARRAY(fcntl_cmds);
427
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300428static const char *fcntl_linux_specific_cmds[] = {
429 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
430 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300431 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300432};
433
434static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
435
436static struct strarray *fcntl_cmds_arrays[] = {
437 &strarray__fcntl_cmds,
438 &strarray__fcntl_linux_specific_cmds,
439};
440
441static DEFINE_STRARRAYS(fcntl_cmds_arrays);
442
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300443static const char *rlimit_resources[] = {
444 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
445 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
446 "RTTIME",
447};
448static DEFINE_STRARRAY(rlimit_resources);
449
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300450static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
451static DEFINE_STRARRAY(sighow);
452
David Ahern4f8c1b72013-09-22 19:45:00 -0600453static const char *clockid[] = {
454 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300455 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
456 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600457};
458static DEFINE_STRARRAY(clockid);
459
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300460static const char *socket_families[] = {
461 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
462 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
463 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
464 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
465 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
466 "ALG", "NFC", "VSOCK",
467};
468static DEFINE_STRARRAY(socket_families);
469
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300470static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
471 struct syscall_arg *arg)
472{
473 size_t printed = 0;
474 int mode = arg->val;
475
476 if (mode == F_OK) /* 0 */
477 return scnprintf(bf, size, "F");
478#define P_MODE(n) \
479 if (mode & n##_OK) { \
480 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
481 mode &= ~n##_OK; \
482 }
483
484 P_MODE(R);
485 P_MODE(W);
486 P_MODE(X);
487#undef P_MODE
488
489 if (mode)
490 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
491
492 return printed;
493}
494
495#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
496
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300497static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
498 struct syscall_arg *arg);
499
500#define SCA_FILENAME syscall_arg__scnprintf_filename
501
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300502static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
503 struct syscall_arg *arg)
504{
505 int printed = 0, flags = arg->val;
506
507#define P_FLAG(n) \
508 if (flags & O_##n) { \
509 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
510 flags &= ~O_##n; \
511 }
512
513 P_FLAG(CLOEXEC);
514 P_FLAG(NONBLOCK);
515#undef P_FLAG
516
517 if (flags)
518 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
519
520 return printed;
521}
522
523#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
524
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300525#ifndef GRND_NONBLOCK
526#define GRND_NONBLOCK 0x0001
527#endif
528#ifndef GRND_RANDOM
529#define GRND_RANDOM 0x0002
530#endif
531
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300532static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
533 struct syscall_arg *arg)
534{
535 int printed = 0, flags = arg->val;
536
537#define P_FLAG(n) \
538 if (flags & GRND_##n) { \
539 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
540 flags &= ~GRND_##n; \
541 }
542
543 P_FLAG(RANDOM);
544 P_FLAG(NONBLOCK);
545#undef P_FLAG
546
547 if (flags)
548 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
549
550 return printed;
551}
552
553#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
554
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300555#define STRARRAY(name, array) \
556 { .scnprintf = SCA_STRARRAY, \
557 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300558
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +0100559#include "trace/beauty/arch_errno_names.c"
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300560#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300561#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300562#include "trace/beauty/futex_val3.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300563#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300564#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300565#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300566#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300567#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300568#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300569#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300570#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300571#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300572#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300573#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300574
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300575struct syscall_arg_fmt {
576 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
577 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300578 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300579 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300580};
581
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300582static struct syscall_fmt {
583 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300584 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300585 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300586 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300587 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300588 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300589 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300590} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300591 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300592 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300593 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300594 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300595 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300596 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300597 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300598 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300599 { .name = "clone", .errpid = true, .nr_args = 5,
600 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
601 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
602 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
603 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
604 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300605 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300606 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300607 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300608 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300609 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300610 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300611 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300612 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300613 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300614 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300615 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300616 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300617 .parm = &strarrays__fcntl_cmds_arrays,
618 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300619 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300620 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300621 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300622 { .name = "fstat", .alias = "newfstat", },
623 { .name = "fstatat", .alias = "newfstatat", },
624 { .name = "futex",
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300625 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
626 [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300627 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300628 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300629 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300630 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300631 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300632 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300633 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300634 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300635 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300636 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo2d1073d2018-01-09 12:03:47 -0300638 { .name = "gettid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300639 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300640 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300641#if defined(__i386__) || defined(__x86_64__)
642/*
643 * FIXME: Make this available to all arches.
644 */
Arnaldo Carvalho de Melo1cc47f22017-07-31 13:20:14 -0300645 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300646 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300647#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300648 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300649#endif
Arnaldo Carvalho de Melo1de30382017-10-31 11:32:23 -0300650 { .name = "kcmp", .nr_args = 5,
651 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
652 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
653 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
654 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
655 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300656 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300657 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300658 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300659 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300660 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300661 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300662 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300663 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300664 { .name = "lstat", .alias = "newlstat", },
665 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300666 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
667 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300668 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300669 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300670 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300671 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300672 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300673 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300676 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200677/* The standard mmap maps to old_mmap on s390x */
678#if defined(__s390x__)
679 .alias = "old_mmap",
680#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300681 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
682 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
683 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300684 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300685 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
686 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300687 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300688 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300689 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300690 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
691 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
692 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300693 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300694 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300695 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300696 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300697 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300698 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300699 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300700 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300701 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300702 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
705 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300706 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300707 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
708 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300710 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
711 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
712 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300715 { .name = "pkey_alloc",
716 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
717 { .name = "pkey_free",
718 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
719 { .name = "pkey_mprotect",
720 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
721 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
722 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300723 { .name = "poll", .timeout = true, },
724 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300725 { .name = "prctl", .alias = "arch_prctl",
726 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
727 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
728 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "pread", .alias = "pread64", },
730 { .name = "preadv", .alias = "pread", },
731 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300732 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300733 { .name = "pwrite", .alias = "pwrite64", },
734 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300735 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300736 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300737 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300738 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300745 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300746 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300747 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300748 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300749 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300750 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
756 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300757 { .name = "select", .timeout = true, },
758 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300759 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300760 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300761 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300764 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300765 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300766 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300767 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300768 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300769 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300770 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300771 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
772 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300773 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300774 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300775 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
776 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300777 { .name = "stat", .alias = "newstat", },
778 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300779 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
780 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
781 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300782 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300783 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300784 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300785 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300786 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300787 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300788 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300789 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300790 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300791 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300792 { .name = "uname", .alias = "newuname", },
793 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300794 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300795 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300796 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300797 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300798 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300799 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300800 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300801};
802
803static int syscall_fmt__cmp(const void *name, const void *fmtp)
804{
805 const struct syscall_fmt *fmt = fmtp;
806 return strcmp(name, fmt->name);
807}
808
809static struct syscall_fmt *syscall_fmt__find(const char *name)
810{
811 const int nmemb = ARRAY_SIZE(syscall_fmts);
812 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
813}
814
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300815/*
816 * is_exit: is this "exit" or "exit_group"?
817 * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
818 */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300819struct syscall {
820 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300821 int nr_args;
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300822 bool is_exit;
823 bool is_open;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300824 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300825 const char *name;
826 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300827 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300828};
829
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300830/*
831 * We need to have this 'calculated' boolean because in some cases we really
832 * don't know what is the duration of a syscall, for instance, when we start
833 * a session and some threads are waiting for a syscall to finish, say 'poll',
834 * in which case all we can do is to print "( ? ) for duration and for the
835 * start timestamp.
836 */
837static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200838{
839 double duration = (double)t / NSEC_PER_MSEC;
840 size_t printed = fprintf(fp, "(");
841
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300842 if (!calculated)
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -0300843 printed += fprintf(fp, " ");
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300844 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200845 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
846 else if (duration >= 0.01)
847 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
848 else
849 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300850 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200851}
852
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300853/**
854 * filename.ptr: The filename char pointer that will be vfs_getname'd
855 * filename.entry_str_pos: Where to insert the string translated from
856 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300857 * ret_scnprintf: syscall args may set this to a different syscall return
858 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300859 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300860struct thread_trace {
861 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300862 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300863 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400864 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300865 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300866 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300867 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300868 struct {
869 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300870 short int entry_str_pos;
871 bool pending_open;
872 unsigned int namelen;
873 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300874 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300875 struct {
876 int max;
877 char **table;
878 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600879
880 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300881};
882
883static struct thread_trace *thread_trace__new(void)
884{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300885 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
886
887 if (ttrace)
888 ttrace->paths.max = -1;
889
David Ahernbf2575c2013-10-08 21:26:53 -0600890 ttrace->syscall_stats = intlist__new(NULL);
891
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300892 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300893}
894
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300895static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300896{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300897 struct thread_trace *ttrace;
898
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300899 if (thread == NULL)
900 goto fail;
901
Namhyung Kim89dceb22014-10-06 09:46:03 +0900902 if (thread__priv(thread) == NULL)
903 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300904
Namhyung Kim89dceb22014-10-06 09:46:03 +0900905 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300906 goto fail;
907
Namhyung Kim89dceb22014-10-06 09:46:03 +0900908 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300909 ++ttrace->nr_events;
910
911 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300913 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300914 "WARNING: not enough memory, dropping samples!\n");
915 return NULL;
916}
917
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300918
919void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300920 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300921{
922 struct thread_trace *ttrace = thread__priv(arg->thread);
923
924 ttrace->ret_scnprintf = ret_scnprintf;
925}
926
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400927#define TRACE_PFMAJ (1 << 0)
928#define TRACE_PFMIN (1 << 1)
929
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300930static const size_t trace__entry_str_size = 2048;
931
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300932static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300933{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900934 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300935
936 if (fd > ttrace->paths.max) {
937 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
938
939 if (npath == NULL)
940 return -1;
941
942 if (ttrace->paths.max != -1) {
943 memset(npath + ttrace->paths.max + 1, 0,
944 (fd - ttrace->paths.max) * sizeof(char *));
945 } else {
946 memset(npath, 0, (fd + 1) * sizeof(char *));
947 }
948
949 ttrace->paths.table = npath;
950 ttrace->paths.max = fd;
951 }
952
953 ttrace->paths.table[fd] = strdup(pathname);
954
955 return ttrace->paths.table[fd] != NULL ? 0 : -1;
956}
957
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300958static int thread__read_fd_path(struct thread *thread, int fd)
959{
960 char linkname[PATH_MAX], pathname[PATH_MAX];
961 struct stat st;
962 int ret;
963
964 if (thread->pid_ == thread->tid) {
965 scnprintf(linkname, sizeof(linkname),
966 "/proc/%d/fd/%d", thread->pid_, fd);
967 } else {
968 scnprintf(linkname, sizeof(linkname),
969 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
970 }
971
972 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
973 return -1;
974
975 ret = readlink(linkname, pathname, sizeof(pathname));
976
977 if (ret < 0 || ret > st.st_size)
978 return -1;
979
980 pathname[ret] = '\0';
981 return trace__set_fd_pathname(thread, fd, pathname);
982}
983
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300984static const char *thread__fd_path(struct thread *thread, int fd,
985 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300986{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900987 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300988
989 if (ttrace == NULL)
990 return NULL;
991
992 if (fd < 0)
993 return NULL;
994
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300995 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300996 if (!trace->live)
997 return NULL;
998 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300999 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001000 return NULL;
1001 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001002
1003 return ttrace->paths.table[fd];
1004}
1005
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001006size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001007{
1008 int fd = arg->val;
1009 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001010 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001011
1012 if (path)
1013 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1014
1015 return printed;
1016}
1017
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -03001018size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1019{
1020 size_t printed = scnprintf(bf, size, "%d", fd);
1021 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1022
1023 if (thread) {
1024 const char *path = thread__fd_path(thread, fd, trace);
1025
1026 if (path)
1027 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1028
1029 thread__put(thread);
1030 }
1031
1032 return printed;
1033}
1034
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001035static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1036 struct syscall_arg *arg)
1037{
1038 int fd = arg->val;
1039 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001040 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001041
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001042 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1043 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001044
1045 return printed;
1046}
1047
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001048static void thread__set_filename_pos(struct thread *thread, const char *bf,
1049 unsigned long ptr)
1050{
1051 struct thread_trace *ttrace = thread__priv(thread);
1052
1053 ttrace->filename.ptr = ptr;
1054 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1055}
1056
1057static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1058 struct syscall_arg *arg)
1059{
1060 unsigned long ptr = arg->val;
1061
1062 if (!arg->trace->vfs_getname)
1063 return scnprintf(bf, size, "%#x", ptr);
1064
1065 thread__set_filename_pos(arg->thread, bf, ptr);
1066 return 0;
1067}
1068
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001069static bool trace__filter_duration(struct trace *trace, double t)
1070{
1071 return t < (trace->duration_filter * NSEC_PER_MSEC);
1072}
1073
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001074static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001075{
1076 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1077
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001078 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001079}
1080
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001081/*
1082 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1083 * using ttrace->entry_time for a thread that receives a sys_exit without
1084 * first having received a sys_enter ("poll" issued before tracing session
1085 * starts, lost sys_enter exit due to ring buffer overflow).
1086 */
1087static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1088{
1089 if (tstamp > 0)
1090 return __trace__fprintf_tstamp(trace, tstamp, fp);
1091
1092 return fprintf(fp, " ? ");
1093}
1094
Namhyung Kimf15eb532012-10-05 14:02:16 +09001095static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001096static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001097
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001098static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001099{
1100 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001101 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001102}
1103
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001105 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001106{
1107 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001108 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001110 if (trace->multiple_threads) {
1111 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001112 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001113 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001114 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001115
1116 return printed;
1117}
1118
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001119static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001120 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121{
1122 int ret = 0;
1123
1124 switch (event->header.type) {
1125 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001126 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001127 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001128 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001129 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001130 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001131 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001132 break;
1133 }
1134
1135 return ret;
1136}
1137
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001138static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001139 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001140 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001141 struct machine *machine)
1142{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001143 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001144 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145}
1146
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001147static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1148{
1149 struct machine *machine = vmachine;
1150
1151 if (machine->kptr_restrict_warned)
1152 return NULL;
1153
1154 if (symbol_conf.kptr_restrict) {
1155 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1156 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1157 "Kernel samples will not be resolved.\n");
1158 machine->kptr_restrict_warned = true;
1159 return NULL;
1160 }
1161
1162 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1163}
1164
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001165static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1166{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001167 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001168
1169 if (err)
1170 return err;
1171
David Ahern8fb598e2013-09-28 13:13:00 -06001172 trace->host = machine__new_host();
1173 if (trace->host == NULL)
1174 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001175
Andrei Vagincbd5c172017-11-07 16:22:46 -08001176 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1177 if (err < 0)
1178 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001179
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001180 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001181 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001182 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001183out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001184 if (err)
1185 symbol__exit();
1186
1187 return err;
1188}
1189
Andrei Vagin33974a42017-11-07 16:22:45 -08001190static void trace__symbols__exit(struct trace *trace)
1191{
1192 machine__exit(trace->host);
1193 trace->host = NULL;
1194
1195 symbol__exit();
1196}
1197
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001198static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1199{
1200 int idx;
1201
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001202 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1203 nr_args = sc->fmt->nr_args;
1204
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001205 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1206 if (sc->arg_fmt == NULL)
1207 return -1;
1208
1209 for (idx = 0; idx < nr_args; ++idx) {
1210 if (sc->fmt)
1211 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1212 }
1213
1214 sc->nr_args = nr_args;
1215 return 0;
1216}
1217
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001218static int syscall__set_arg_fmts(struct syscall *sc)
1219{
1220 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001221 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001222
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001223 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001224 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1225 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001226
1227 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001228 (strcmp(field->name, "filename") == 0 ||
1229 strcmp(field->name, "path") == 0 ||
1230 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001231 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001232 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001233 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001234 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001235 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001236 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001237 sc->arg_fmt[idx].scnprintf = 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 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001250 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001251 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001252 }
1253
1254 return 0;
1255}
1256
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001257static int trace__read_syscall_info(struct trace *trace, int id)
1258{
1259 char tp_name[128];
1260 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001261 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001262
1263 if (name == NULL)
1264 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001265
1266 if (id > trace->syscalls.max) {
1267 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1268
1269 if (nsyscalls == NULL)
1270 return -1;
1271
1272 if (trace->syscalls.max != -1) {
1273 memset(nsyscalls + trace->syscalls.max + 1, 0,
1274 (id - trace->syscalls.max) * sizeof(*sc));
1275 } else {
1276 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1277 }
1278
1279 trace->syscalls.table = nsyscalls;
1280 trace->syscalls.max = id;
1281 }
1282
1283 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001284 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001285
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001286 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001287
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001288 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001289 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001290
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001291 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001292 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001293 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001294 }
1295
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001296 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1297 return -1;
1298
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001299 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001300 return -1;
1301
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001302 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001303 /*
1304 * We need to check and discard the first variable '__syscall_nr'
1305 * or 'nr' that mean the syscall number. It is needless here.
1306 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1307 */
1308 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001309 sc->args = sc->args->next;
1310 --sc->nr_args;
1311 }
1312
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001313 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001314 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001315
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001316 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001317}
1318
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001319static int trace__validate_ev_qualifier(struct trace *trace)
1320{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001321 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001322 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001323 struct str_node *pos;
1324
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001325 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1326 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1327 sizeof(trace->ev_qualifier_ids.entries[0]));
1328
1329 if (trace->ev_qualifier_ids.entries == NULL) {
1330 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1331 trace->output);
1332 err = -EINVAL;
1333 goto out;
1334 }
1335
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001336 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001337 i = 0;
1338
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001339 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001340 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001341 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001342
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001343 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001344 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1345 if (id >= 0)
1346 goto matches;
1347
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001348 if (err == 0) {
1349 fputs("Error:\tInvalid syscall ", trace->output);
1350 err = -EINVAL;
1351 } else {
1352 fputs(", ", trace->output);
1353 }
1354
1355 fputs(sc, trace->output);
1356 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001357matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001358 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001359 if (match_next == -1)
1360 continue;
1361
1362 while (1) {
1363 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1364 if (id < 0)
1365 break;
1366 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1367 void *entries;
1368
1369 nr_allocated += 8;
1370 entries = realloc(trace->ev_qualifier_ids.entries,
1371 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1372 if (entries == NULL) {
1373 err = -ENOMEM;
1374 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1375 goto out_free;
1376 }
1377 trace->ev_qualifier_ids.entries = entries;
1378 }
1379 trace->ev_qualifier_ids.nr++;
1380 trace->ev_qualifier_ids.entries[i++] = id;
1381 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001382 }
1383
1384 if (err < 0) {
1385 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1386 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001387out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001388 zfree(&trace->ev_qualifier_ids.entries);
1389 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001390 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001391out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001392 return err;
1393}
1394
David Ahern55d43bca2015-02-19 15:00:22 -05001395/*
1396 * args is to be interpreted as a series of longs but we need to handle
1397 * 8-byte unaligned accesses. args points to raw_data within the event
1398 * and raw_data is guaranteed to be 8-byte unaligned because it is
1399 * preceded by raw_size which is a u32. So we need to copy args to a temp
1400 * variable to read it. Most notably this avoids extended load instructions
1401 * on unaligned addresses
1402 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001403unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001404{
1405 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001406 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001407
1408 memcpy(&val, p, sizeof(val));
1409 return val;
1410}
1411
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001412static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1413 struct syscall_arg *arg)
1414{
1415 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1416 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1417
1418 return scnprintf(bf, size, "arg%d: ", arg->idx);
1419}
1420
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001421static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1422 struct syscall_arg *arg, unsigned long val)
1423{
1424 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1425 arg->val = val;
1426 if (sc->arg_fmt[arg->idx].parm)
1427 arg->parm = sc->arg_fmt[arg->idx].parm;
1428 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1429 }
1430 return scnprintf(bf, size, "%ld", val);
1431}
1432
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001433static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001434 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001435 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001436{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001437 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001438 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001439 u8 bit = 1;
1440 struct syscall_arg arg = {
1441 .args = args,
1442 .idx = 0,
1443 .mask = 0,
1444 .trace = trace,
1445 .thread = thread,
1446 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001447 struct thread_trace *ttrace = thread__priv(thread);
1448
1449 /*
1450 * Things like fcntl will set this in its 'cmd' formatter to pick the
1451 * right formatter for the return value (an fd? file flags?), which is
1452 * not needed for syscalls that always return a given type, say an fd.
1453 */
1454 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001455
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001456 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001457 struct format_field *field;
1458
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001459 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001460 field = field->next, ++arg.idx, bit <<= 1) {
1461 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001462 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001463
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001464 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001465
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001466 /*
1467 * Suppress this argument if its value is zero and
1468 * and we don't have a string associated in an
1469 * strarray for it.
1470 */
David Ahern55d43bca2015-02-19 15:00:22 -05001471 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001472 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001473 (sc->arg_fmt[arg.idx].show_zero ||
1474 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001475 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1476 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001477 continue;
1478
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001479 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001480 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001481 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001482 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001483 } else if (IS_ERR(sc->tp_format)) {
1484 /*
1485 * If we managed to read the tracepoint /format file, then we
1486 * may end up not having any args, like with gettid(), so only
1487 * print the raw args when we didn't manage to read it.
1488 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001489 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001490 if (arg.mask & bit)
1491 goto next_arg;
1492 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001493 if (printed)
1494 printed += scnprintf(bf + printed, size - printed, ", ");
1495 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001496 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1497next_arg:
1498 ++arg.idx;
1499 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001500 }
1501 }
1502
1503 return printed;
1504}
1505
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001506typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001507 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001508 struct perf_sample *sample);
1509
1510static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001511 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001512{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001513
1514 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001515
1516 /*
1517 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1518 * before that, leaving at a higher verbosity level till that is
1519 * explained. Reproduced with plain ftrace with:
1520 *
1521 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1522 * grep "NR -1 " /t/trace_pipe
1523 *
1524 * After generating some load on the machine.
1525 */
1526 if (verbose > 1) {
1527 static u64 n;
1528 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1529 id, perf_evsel__name(evsel), ++n);
1530 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001531 return NULL;
1532 }
1533
1534 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1535 trace__read_syscall_info(trace, id))
1536 goto out_cant_read;
1537
1538 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1539 goto out_cant_read;
1540
1541 return &trace->syscalls.table[id];
1542
1543out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001544 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001545 fprintf(trace->output, "Problems reading syscall %d", id);
1546 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1547 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1548 fputs(" information\n", trace->output);
1549 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001550 return NULL;
1551}
1552
David Ahernbf2575c2013-10-08 21:26:53 -06001553static void thread__update_stats(struct thread_trace *ttrace,
1554 int id, struct perf_sample *sample)
1555{
1556 struct int_node *inode;
1557 struct stats *stats;
1558 u64 duration = 0;
1559
1560 inode = intlist__findnew(ttrace->syscall_stats, id);
1561 if (inode == NULL)
1562 return;
1563
1564 stats = inode->priv;
1565 if (stats == NULL) {
1566 stats = malloc(sizeof(struct stats));
1567 if (stats == NULL)
1568 return;
1569 init_stats(stats);
1570 inode->priv = stats;
1571 }
1572
1573 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1574 duration = sample->time - ttrace->entry_time;
1575
1576 update_stats(stats, duration);
1577}
1578
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001579static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001580{
1581 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001582 size_t printed;
1583
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001584 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001585 return 0;
1586
1587 ttrace = thread__priv(trace->current);
1588
1589 if (!ttrace->entry_pending)
1590 return 0;
1591
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001592 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001593 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1594 ttrace->entry_pending = false;
1595
1596 return printed;
1597}
1598
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001599static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1600 struct perf_sample *sample, struct thread *thread)
1601{
1602 int printed = 0;
1603
1604 if (trace->print_sample) {
1605 double ts = (double)sample->time / NSEC_PER_MSEC;
1606
1607 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1608 perf_evsel__name(evsel), ts,
1609 thread__comm_str(thread),
1610 sample->pid, sample->tid, sample->cpu);
1611 }
1612
1613 return printed;
1614}
1615
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001616static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001617 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001618 struct perf_sample *sample)
1619{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001620 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001621 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001622 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001623 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001624 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001625 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001626 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001627
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001628 if (sc == NULL)
1629 return -1;
1630
David Ahern8fb598e2013-09-28 13:13:00 -06001631 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001632 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001633 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001634 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001635
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001636 trace__fprintf_sample(trace, evsel, sample, thread);
1637
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001638 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001639
1640 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001641 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001642 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001643 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001644 }
1645
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001646 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001647 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001648
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001649 ttrace->entry_time = sample->time;
1650 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001651 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001652
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001653 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001654 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001655
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001656 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001657 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001658 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001659 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001660 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001661 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001662 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001663 /* See trace__vfs_getname & trace__sys_exit */
1664 ttrace->filename.pending_open = false;
1665 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001666
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001667 if (trace->current != thread) {
1668 thread__put(trace->current);
1669 trace->current = thread__get(thread);
1670 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001671 err = 0;
1672out_put:
1673 thread__put(thread);
1674 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001675}
1676
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001677static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1678 struct perf_sample *sample)
1679{
1680 struct format_field *field = perf_evsel__field(evsel, "__syscall_nr");
1681 struct thread_trace *ttrace;
1682 struct thread *thread;
1683 struct syscall *sc;
1684 char msg[1024];
1685 int id, err = -1;
1686 void *args;
1687
1688 if (field == NULL)
1689 return -1;
1690
1691 id = format_field__intval(field, sample, evsel->needs_swap);
1692 sc = trace__syscall_info(trace, evsel, id);
1693
1694 if (sc == NULL)
1695 return -1;
1696
1697 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1698 ttrace = thread__trace(thread, trace->output);
1699 /*
1700 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1701 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1702 */
1703 if (ttrace == NULL)
1704 goto out_put;
1705
1706 args = sample->raw_data + field->offset + sizeof(u64); /* skip __syscall_nr, there is where args are */
1707 syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread);
1708 fprintf(trace->output, "%s", msg);
1709 err = 0;
1710out_put:
1711 thread__put(thread);
1712 return err;
1713}
1714
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001715static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1716 struct perf_sample *sample,
1717 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001718{
1719 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301720 int max_stack = evsel->attr.sample_max_stack ?
1721 evsel->attr.sample_max_stack :
1722 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001723
1724 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301725 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001726 return -1;
1727
1728 return 0;
1729}
1730
1731static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1732{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001733 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001734 const unsigned int print_opts = EVSEL__PRINT_SYM |
1735 EVSEL__PRINT_DSO |
1736 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001737
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001738 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001739}
1740
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001741static const char *errno_to_name(struct perf_evsel *evsel, int err)
1742{
1743 struct perf_env *env = perf_evsel__env(evsel);
1744 const char *arch_name = perf_env__arch(env);
1745
1746 return arch_syscalls__strerrno(arch_name, err);
1747}
1748
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001749static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001750 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001751 struct perf_sample *sample)
1752{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001753 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001754 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001755 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001756 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001757 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001758 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001759 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001760
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001761 if (sc == NULL)
1762 return -1;
1763
David Ahern8fb598e2013-09-28 13:13:00 -06001764 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001765 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001766 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001767 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001768
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001769 trace__fprintf_sample(trace, evsel, sample, thread);
1770
David Ahernbf2575c2013-10-08 21:26:53 -06001771 if (trace->summary)
1772 thread__update_stats(ttrace, id, sample);
1773
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001774 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001775
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001776 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001777 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1778 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001779 ++trace->stats.vfs_getname;
1780 }
1781
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001782 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001783 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001784 if (trace__filter_duration(trace, duration))
1785 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001786 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001787 } else if (trace->duration_filter)
1788 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001789
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001790 if (sample->callchain) {
1791 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1792 if (callchain_ret == 0) {
1793 if (callchain_cursor.nr < trace->min_stack)
1794 goto out;
1795 callchain_ret = 1;
1796 }
1797 }
1798
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001799 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001800 goto out;
1801
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001802 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001803
1804 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001805 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001806 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001807 fprintf(trace->output, " ... [");
1808 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1809 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001810 }
1811
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001812 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001813 if (ret < 0)
1814 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001815signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001816 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001817 } else if (ret < 0) {
1818errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001819 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001820 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001821 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001822
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001823 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001824 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001825 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001826 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001827 else if (ttrace->ret_scnprintf) {
1828 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001829 struct syscall_arg arg = {
1830 .val = ret,
1831 .thread = thread,
1832 .trace = trace,
1833 };
1834 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001835 ttrace->ret_scnprintf = NULL;
1836 fprintf(trace->output, ") = %s", bf);
1837 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001838 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001839 else if (sc->fmt->errpid) {
1840 struct thread *child = machine__find_thread(trace->host, ret, ret);
1841
1842 if (child != NULL) {
1843 fprintf(trace->output, ") = %ld", ret);
1844 if (child->comm_set)
1845 fprintf(trace->output, " (%s)", thread__comm_str(child));
1846 thread__put(child);
1847 }
1848 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001849 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001850
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001851 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001852
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001853 if (callchain_ret > 0)
1854 trace__fprintf_callchain(trace, sample);
1855 else if (callchain_ret < 0)
1856 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001857out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001858 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001859 err = 0;
1860out_put:
1861 thread__put(thread);
1862 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001863}
1864
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001865static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001866 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001867 struct perf_sample *sample)
1868{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001869 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1870 struct thread_trace *ttrace;
1871 size_t filename_len, entry_str_len, to_move;
1872 ssize_t remaining_space;
1873 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001874 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001875
1876 if (!thread)
1877 goto out;
1878
1879 ttrace = thread__priv(thread);
1880 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001881 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001882
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001883 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001884 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001885 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001886
1887 if (ttrace->filename.namelen < filename_len) {
1888 char *f = realloc(ttrace->filename.name, filename_len + 1);
1889
1890 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001891 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001892
1893 ttrace->filename.namelen = filename_len;
1894 ttrace->filename.name = f;
1895 }
1896
1897 strcpy(ttrace->filename.name, filename);
1898 ttrace->filename.pending_open = true;
1899
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001900 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001901 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001902
1903 entry_str_len = strlen(ttrace->entry_str);
1904 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1905 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001906 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001907
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001908 if (filename_len > (size_t)remaining_space) {
1909 filename += filename_len - remaining_space;
1910 filename_len = remaining_space;
1911 }
1912
1913 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1914 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1915 memmove(pos + filename_len, pos, to_move);
1916 memcpy(pos, filename, filename_len);
1917
1918 ttrace->filename.ptr = 0;
1919 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001920out_put:
1921 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001922out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001923 return 0;
1924}
1925
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001926static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001927 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001928 struct perf_sample *sample)
1929{
1930 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1931 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001932 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001933 sample->pid,
1934 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001935 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001936
1937 if (ttrace == NULL)
1938 goto out_dump;
1939
1940 ttrace->runtime_ms += runtime_ms;
1941 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001942out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001943 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001944 return 0;
1945
1946out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001947 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001948 evsel->name,
1949 perf_evsel__strval(evsel, sample, "comm"),
1950 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1951 runtime,
1952 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001953 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001954}
1955
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001956static int bpf_output__printer(enum binary_printer_ops op,
1957 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001958{
Wang Nan1d6c9402016-02-26 09:31:55 +00001959 unsigned char ch = (unsigned char)val;
1960
1961 switch (op) {
1962 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001963 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001964 case BINARY_PRINT_DATA_BEGIN:
1965 case BINARY_PRINT_LINE_BEGIN:
1966 case BINARY_PRINT_ADDR:
1967 case BINARY_PRINT_NUM_DATA:
1968 case BINARY_PRINT_NUM_PAD:
1969 case BINARY_PRINT_SEP:
1970 case BINARY_PRINT_CHAR_PAD:
1971 case BINARY_PRINT_LINE_END:
1972 case BINARY_PRINT_DATA_END:
1973 default:
1974 break;
1975 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001976
1977 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001978}
1979
1980static void bpf_output__fprintf(struct trace *trace,
1981 struct perf_sample *sample)
1982{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001983 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1984 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001985}
1986
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001987static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1988 union perf_event *event __maybe_unused,
1989 struct perf_sample *sample)
1990{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001991 int callchain_ret = 0;
1992
1993 if (sample->callchain) {
1994 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1995 if (callchain_ret == 0) {
1996 if (callchain_cursor.nr < trace->min_stack)
1997 goto out;
1998 callchain_ret = 1;
1999 }
2000 }
2001
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03002002 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002003 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002004
2005 if (trace->trace_syscalls)
2006 fprintf(trace->output, "( ): ");
2007
2008 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002009
Wang Nan1d6c9402016-02-26 09:31:55 +00002010 if (perf_evsel__is_bpf_output(evsel)) {
2011 bpf_output__fprintf(trace, sample);
2012 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002013 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2014 trace__fprintf_sys_enter(trace, evsel, sample)) {
2015 event_format__fprintf(evsel->tp_format, sample->cpu,
2016 sample->raw_data, sample->raw_size,
2017 trace->output);
2018 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002019 }
2020
Changbin Du51125a22018-03-13 18:40:01 +08002021 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002022
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002023 if (callchain_ret > 0)
2024 trace__fprintf_callchain(trace, sample);
2025 else if (callchain_ret < 0)
2026 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2027out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002028 return 0;
2029}
2030
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002031static void print_location(FILE *f, struct perf_sample *sample,
2032 struct addr_location *al,
2033 bool print_dso, bool print_sym)
2034{
2035
Namhyung Kimbb963e12017-02-17 17:17:38 +09002036 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002037 fprintf(f, "%s@", al->map->dso->long_name);
2038
Namhyung Kimbb963e12017-02-17 17:17:38 +09002039 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002040 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002041 al->addr - al->sym->start);
2042 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002043 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002044 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002045 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002046}
2047
2048static int trace__pgfault(struct trace *trace,
2049 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002050 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002051 struct perf_sample *sample)
2052{
2053 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002054 struct addr_location al;
2055 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002056 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002057 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002058 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002059
2060 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002061
2062 if (sample->callchain) {
2063 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2064 if (callchain_ret == 0) {
2065 if (callchain_cursor.nr < trace->min_stack)
2066 goto out_put;
2067 callchain_ret = 1;
2068 }
2069 }
2070
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002071 ttrace = thread__trace(thread, trace->output);
2072 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002073 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002074
2075 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2076 ttrace->pfmaj++;
2077 else
2078 ttrace->pfmin++;
2079
2080 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002081 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002082
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002083 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002084
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002085 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002086
2087 fprintf(trace->output, "%sfault [",
2088 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2089 "maj" : "min");
2090
2091 print_location(trace->output, sample, &al, false, true);
2092
2093 fprintf(trace->output, "] => ");
2094
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002095 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002096
2097 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002098 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002099
2100 if (al.map)
2101 map_type = 'x';
2102 else
2103 map_type = '?';
2104 }
2105
2106 print_location(trace->output, sample, &al, true, false);
2107
2108 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002109
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002110 if (callchain_ret > 0)
2111 trace__fprintf_callchain(trace, sample);
2112 else if (callchain_ret < 0)
2113 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002114out:
2115 err = 0;
2116out_put:
2117 thread__put(thread);
2118 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002119}
2120
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002121static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002122 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002123 struct perf_sample *sample)
2124{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002125 /*
2126 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2127 * and don't use sample->time unconditionally, we may end up having
2128 * some other event in the future without PERF_SAMPLE_TIME for good
2129 * reason, i.e. we may not be interested in its timestamps, just in
2130 * it taking place, picking some piece of information when it
2131 * appears in our event stream (vfs_getname comes to mind).
2132 */
2133 if (trace->base_time == 0 && !trace->full_time &&
2134 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002135 trace->base_time = sample->time;
2136}
2137
David Ahern6810fc92013-08-28 22:29:52 -06002138static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002139 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002140 struct perf_sample *sample,
2141 struct perf_evsel *evsel,
2142 struct machine *machine __maybe_unused)
2143{
2144 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002145 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002146 int err = 0;
2147
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002148 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002149
David Ahernaa07df62016-11-25 09:29:52 -07002150 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2151 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002152 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002153
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002154 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002155
David Ahern31605652013-12-04 19:41:41 -07002156 if (handler) {
2157 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002158 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002159 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002160out:
2161 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002162 return err;
2163}
2164
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002165static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002166{
2167 unsigned int rec_argc, i, j;
2168 const char **rec_argv;
2169 const char * const record_args[] = {
2170 "record",
2171 "-R",
2172 "-m", "1024",
2173 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002174 };
2175
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002176 const char * const sc_args[] = { "-e", };
2177 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2178 const char * const majpf_args[] = { "-e", "major-faults" };
2179 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2180 const char * const minpf_args[] = { "-e", "minor-faults" };
2181 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2182
David Ahern9aca7f12013-12-04 19:41:39 -07002183 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002184 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2185 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002186 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2187
2188 if (rec_argv == NULL)
2189 return -ENOMEM;
2190
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002191 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002192 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002193 rec_argv[j++] = record_args[i];
2194
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002195 if (trace->trace_syscalls) {
2196 for (i = 0; i < sc_args_nr; i++)
2197 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002198
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002199 /* event string may be different for older kernels - e.g., RHEL6 */
2200 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2201 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2202 else if (is_valid_tracepoint("syscalls:sys_enter"))
2203 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2204 else {
2205 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002206 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002207 return -1;
2208 }
David Ahern9aca7f12013-12-04 19:41:39 -07002209 }
David Ahern9aca7f12013-12-04 19:41:39 -07002210
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002211 if (trace->trace_pgfaults & TRACE_PFMAJ)
2212 for (i = 0; i < majpf_args_nr; i++)
2213 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002214
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002215 if (trace->trace_pgfaults & TRACE_PFMIN)
2216 for (i = 0; i < minpf_args_nr; i++)
2217 rec_argv[j++] = minpf_args[i];
2218
2219 for (i = 0; i < (unsigned int)argc; i++)
2220 rec_argv[j++] = argv[i];
2221
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002222 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002223}
2224
David Ahernbf2575c2013-10-08 21:26:53 -06002225static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2226
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002227static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002228{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002229 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002230
2231 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002232 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002233
2234 if (perf_evsel__field(evsel, "pathname") == NULL) {
2235 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002236 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002237 }
2238
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002239 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002240 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002241 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002242}
2243
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002244static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002245{
2246 struct perf_evsel *evsel;
2247 struct perf_event_attr attr = {
2248 .type = PERF_TYPE_SOFTWARE,
2249 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002250 };
2251
2252 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002253 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002254
2255 event_attr_init(&attr);
2256
2257 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002258 if (evsel)
2259 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002260
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002261 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002262}
2263
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002264static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2265{
2266 const u32 type = event->header.type;
2267 struct perf_evsel *evsel;
2268
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002269 if (type != PERF_RECORD_SAMPLE) {
2270 trace__process_event(trace, trace->host, event, sample);
2271 return;
2272 }
2273
2274 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2275 if (evsel == NULL) {
2276 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2277 return;
2278 }
2279
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002280 trace__set_base_time(trace, evsel, sample);
2281
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002282 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2283 sample->raw_data == NULL) {
2284 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2285 perf_evsel__name(evsel), sample->tid,
2286 sample->cpu, sample->raw_size);
2287 } else {
2288 tracepoint_handler handler = evsel->handler;
2289 handler(trace, evsel, event, sample);
2290 }
2291}
2292
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002293static int trace__add_syscall_newtp(struct trace *trace)
2294{
2295 int ret = -1;
2296 struct perf_evlist *evlist = trace->evlist;
2297 struct perf_evsel *sys_enter, *sys_exit;
2298
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002299 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002300 if (sys_enter == NULL)
2301 goto out;
2302
2303 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2304 goto out_delete_sys_enter;
2305
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002306 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002307 if (sys_exit == NULL)
2308 goto out_delete_sys_enter;
2309
2310 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2311 goto out_delete_sys_exit;
2312
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002313 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2314 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2315
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002316 perf_evlist__add(evlist, sys_enter);
2317 perf_evlist__add(evlist, sys_exit);
2318
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002319 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002320 /*
2321 * We're interested only in the user space callchain
2322 * leading to the syscall, allow overriding that for
2323 * debugging reasons using --kernel_syscall_callchains
2324 */
2325 sys_exit->attr.exclude_callchain_kernel = 1;
2326 }
2327
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002328 trace->syscalls.events.sys_enter = sys_enter;
2329 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002330
2331 ret = 0;
2332out:
2333 return ret;
2334
2335out_delete_sys_exit:
2336 perf_evsel__delete_priv(sys_exit);
2337out_delete_sys_enter:
2338 perf_evsel__delete_priv(sys_enter);
2339 goto out;
2340}
2341
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002342static int trace__set_ev_qualifier_filter(struct trace *trace)
2343{
2344 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002345 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002346 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2347 trace->ev_qualifier_ids.nr,
2348 trace->ev_qualifier_ids.entries);
2349
2350 if (filter == NULL)
2351 goto out_enomem;
2352
Mathieu Poirier3541c032016-09-16 08:44:04 -06002353 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2354 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002355 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002356 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002357 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002358
2359 free(filter);
2360out:
2361 return err;
2362out_enomem:
2363 errno = ENOMEM;
2364 goto out;
2365}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002366
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002367static int trace__set_filter_loop_pids(struct trace *trace)
2368{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002369 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002370 pid_t pids[32] = {
2371 getpid(),
2372 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002373 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2374
2375 while (thread && nr < ARRAY_SIZE(pids)) {
2376 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2377
2378 if (parent == NULL)
2379 break;
2380
2381 if (!strcmp(thread__comm_str(parent), "sshd")) {
2382 pids[nr++] = parent->tid;
2383 break;
2384 }
2385 thread = parent;
2386 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002387
2388 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2389}
2390
Namhyung Kimf15eb532012-10-05 14:02:16 +09002391static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002392{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002393 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002394 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002395 int err = -1, i;
2396 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002397 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002398 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002399
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002400 trace->live = true;
2401
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002402 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002403 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002404
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002405 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002406 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002407
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002408 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2409 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2410 if (pgfault_maj == NULL)
2411 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002412 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002413 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002414 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002415
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002416 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2417 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2418 if (pgfault_min == NULL)
2419 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002420 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002421 perf_evlist__add(evlist, pgfault_min);
2422 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002423
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002424 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002425 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2426 trace__sched_stat_runtime))
2427 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002428
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002429 /*
2430 * If a global cgroup was set, apply it to all the events without an
2431 * explicit cgroup. I.e.:
2432 *
2433 * trace -G A -e sched:*switch
2434 *
2435 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2436 * _and_ sched:sched_switch to the 'A' cgroup, while:
2437 *
2438 * trace -e sched:*switch -G A
2439 *
2440 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2441 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2442 * a cgroup (on the root cgroup, sys wide, etc).
2443 *
2444 * Multiple cgroups:
2445 *
2446 * trace -G A -e sched:*switch -G B
2447 *
2448 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2449 * to the 'B' cgroup.
2450 *
2451 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2452 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2453 */
2454 if (trace->cgroup)
2455 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2456
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002457 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2458 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002459 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002460 goto out_delete_evlist;
2461 }
2462
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002463 err = trace__symbols_init(trace, evlist);
2464 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002465 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002466 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002467 }
2468
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002469 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002470
Namhyung Kimf15eb532012-10-05 14:02:16 +09002471 signal(SIGCHLD, sig_handler);
2472 signal(SIGINT, sig_handler);
2473
2474 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002475 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002476 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002477 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002478 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002479 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002480 }
2481 }
2482
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002483 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002484 if (err < 0)
2485 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002486
Wang Nanba504232016-02-26 09:31:54 +00002487 err = bpf__apply_obj_config();
2488 if (err) {
2489 char errbuf[BUFSIZ];
2490
2491 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2492 pr_err("ERROR: Apply config to BPF failed: %s\n",
2493 errbuf);
2494 goto out_error_open;
2495 }
2496
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002497 /*
2498 * Better not use !target__has_task() here because we need to cover the
2499 * case where no threads were specified in the command line, but a
2500 * workload was, and in that case we will fill in the thread_map when
2501 * we fork the workload in perf_evlist__prepare_workload.
2502 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002503 if (trace->filter_pids.nr > 0)
2504 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002505 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002506 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002507
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002508 if (err < 0)
2509 goto out_error_mem;
2510
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002511 if (trace->ev_qualifier_ids.nr > 0) {
2512 err = trace__set_ev_qualifier_filter(trace);
2513 if (err < 0)
2514 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002515
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002516 pr_debug("event qualifier tracepoint filter: %s\n",
2517 trace->syscalls.events.sys_exit->filter);
2518 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002519
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002520 err = perf_evlist__apply_filters(evlist, &evsel);
2521 if (err < 0)
2522 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002523
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002524 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002525 if (err < 0)
2526 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002527
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002528 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002529 perf_evlist__enable(evlist);
2530
Namhyung Kimf15eb532012-10-05 14:02:16 +09002531 if (forks)
2532 perf_evlist__start_workload(evlist);
2533
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002534 if (trace->opts.initial_delay) {
2535 usleep(trace->opts.initial_delay * 1000);
2536 perf_evlist__enable(evlist);
2537 }
2538
Jiri Olsae13798c2015-06-23 00:36:02 +02002539 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002540 evlist->threads->nr > 1 ||
2541 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002542
2543 /*
2544 * Now that we already used evsel->attr to ask the kernel to setup the
2545 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2546 * trace__resolve_callchain(), allowing per-event max-stack settings
2547 * to override an explicitely set --max-stack global setting.
2548 */
2549 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002550 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002551 evsel->attr.sample_max_stack == 0)
2552 evsel->attr.sample_max_stack = trace->max_stack;
2553 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002554again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002555 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002556
2557 for (i = 0; i < evlist->nr_mmaps; i++) {
2558 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002559 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002560
Kan Liangd7f55c62018-03-01 18:08:59 -05002561 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002562 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002563 continue;
2564
Kan Liang0019dc872018-03-06 10:36:06 -05002565 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002566 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002567
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002568 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002569
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002570 err = perf_evlist__parse_sample(evlist, event, &sample);
2571 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002572 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002573 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002574 }
2575
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002576 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002577next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002578 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002579
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002580 if (interrupted)
2581 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002582
2583 if (done && !draining) {
2584 perf_evlist__disable(evlist);
2585 draining = true;
2586 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002587 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002588 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002589 }
2590
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002591 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002592 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002593
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002594 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2595 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2596 draining = true;
2597
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002598 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002599 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002600 } else {
2601 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002602 }
2603
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002604out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002605 thread__zput(trace->current);
2606
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002607 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002608
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002609 if (!err) {
2610 if (trace->summary)
2611 trace__fprintf_thread_summary(trace, trace->output);
2612
2613 if (trace->show_tool_stats) {
2614 fprintf(trace->output, "Stats:\n "
2615 " vfs_getname : %" PRIu64 "\n"
2616 " proc_getname: %" PRIu64 "\n",
2617 trace->stats.vfs_getname,
2618 trace->stats.proc_getname);
2619 }
2620 }
David Ahernbf2575c2013-10-08 21:26:53 -06002621
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002622out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002623 trace__symbols__exit(trace);
2624
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002625 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002626 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002627 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002628 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002629 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002630{
2631 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002632
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002633out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002634 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002635 goto out_error;
2636
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002637out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002638 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002639 goto out_error;
2640
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002641out_error_mmap:
2642 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2643 goto out_error;
2644
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002645out_error_open:
2646 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2647
2648out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002649 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302650 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002651
2652out_error_apply_filters:
2653 fprintf(trace->output,
2654 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2655 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002656 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002657 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002658}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002659out_error_mem:
2660 fprintf(trace->output, "Not enough memory to run!\n");
2661 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002662
2663out_errno:
2664 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2665 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002666}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002667
David Ahern6810fc92013-08-28 22:29:52 -06002668static int trace__replay(struct trace *trace)
2669{
2670 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002671 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002672 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002673 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002674 .file = {
2675 .path = input_name,
2676 },
2677 .mode = PERF_DATA_MODE_READ,
2678 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002679 };
David Ahern6810fc92013-08-28 22:29:52 -06002680 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002681 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002682 int err = -1;
2683
2684 trace->tool.sample = trace__process_sample;
2685 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002686 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002687 trace->tool.comm = perf_event__process_comm;
2688 trace->tool.exit = perf_event__process_exit;
2689 trace->tool.fork = perf_event__process_fork;
2690 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302691 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002692 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302693 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002694
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002695 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002696 trace->tool.ordering_requires_timestamps = true;
2697
2698 /* add tid to output */
2699 trace->multiple_threads = true;
2700
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002701 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002702 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002703 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002704
David Ahernaa07df62016-11-25 09:29:52 -07002705 if (trace->opts.target.pid)
2706 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2707
2708 if (trace->opts.target.tid)
2709 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2710
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002711 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002712 goto out;
2713
David Ahern8fb598e2013-09-28 13:13:00 -06002714 trace->host = &session->machines.host;
2715
David Ahern6810fc92013-08-28 22:29:52 -06002716 err = perf_session__set_tracepoints_handlers(session, handlers);
2717 if (err)
2718 goto out;
2719
Namhyung Kim003824e2013-11-12 15:25:00 +09002720 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2721 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002722 /* older kernels have syscalls tp versus raw_syscalls */
2723 if (evsel == NULL)
2724 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2725 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002726
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002727 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002728 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002729 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002730 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2731 goto out;
2732 }
2733
2734 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2735 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002736 if (evsel == NULL)
2737 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2738 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002739 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002740 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002741 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002742 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002743 goto out;
2744 }
2745
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002746 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002747 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2748 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2749 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2750 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2751 evsel->handler = trace__pgfault;
2752 }
2753
David Ahern6810fc92013-08-28 22:29:52 -06002754 setup_pager();
2755
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002756 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002757 if (err)
2758 pr_err("Failed to process events, error %d", err);
2759
David Ahernbf2575c2013-10-08 21:26:53 -06002760 else if (trace->summary)
2761 trace__fprintf_thread_summary(trace, trace->output);
2762
David Ahern6810fc92013-08-28 22:29:52 -06002763out:
2764 perf_session__delete(session);
2765
2766 return err;
2767}
2768
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002769static size_t trace__fprintf_threads_header(FILE *fp)
2770{
2771 size_t printed;
2772
Pekka Enberg99ff7152013-11-12 16:42:14 +02002773 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002774
2775 return printed;
2776}
2777
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002778DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2779 struct stats *stats;
2780 double msecs;
2781 int syscall;
2782)
2783{
2784 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2785 struct stats *stats = source->priv;
2786
2787 entry->syscall = source->i;
2788 entry->stats = stats;
2789 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2790}
2791
David Ahernbf2575c2013-10-08 21:26:53 -06002792static size_t thread__dump_stats(struct thread_trace *ttrace,
2793 struct trace *trace, FILE *fp)
2794{
David Ahernbf2575c2013-10-08 21:26:53 -06002795 size_t printed = 0;
2796 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002797 struct rb_node *nd;
2798 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002799
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002800 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002801 return 0;
2802
2803 printed += fprintf(fp, "\n");
2804
Milian Wolff834fd462015-08-06 11:24:29 +02002805 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2806 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2807 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002808
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002809 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002810 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002811 if (stats) {
2812 double min = (double)(stats->min) / NSEC_PER_MSEC;
2813 double max = (double)(stats->max) / NSEC_PER_MSEC;
2814 double avg = avg_stats(stats);
2815 double pct;
2816 u64 n = (u64) stats->n;
2817
2818 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2819 avg /= NSEC_PER_MSEC;
2820
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002821 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002822 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002823 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002824 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002825 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002826 }
David Ahernbf2575c2013-10-08 21:26:53 -06002827 }
2828
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002829 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002830 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002831
2832 return printed;
2833}
2834
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002835static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002836{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002837 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002838 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002839 double ratio;
2840
2841 if (ttrace == NULL)
2842 return 0;
2843
2844 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2845
Pekka Enberg15e65c62013-11-14 18:43:30 +02002846 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002847 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002848 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002849 if (ttrace->pfmaj)
2850 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2851 if (ttrace->pfmin)
2852 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002853 if (trace->sched)
2854 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2855 else if (fputc('\n', fp) != EOF)
2856 ++printed;
2857
David Ahernbf2575c2013-10-08 21:26:53 -06002858 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002859
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002860 return printed;
2861}
David Ahern896cbb52013-09-28 13:12:59 -06002862
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002863static unsigned long thread__nr_events(struct thread_trace *ttrace)
2864{
2865 return ttrace ? ttrace->nr_events : 0;
2866}
2867
2868DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2869 struct thread *thread;
2870)
2871{
2872 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002873}
2874
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002875static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2876{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002877 size_t printed = trace__fprintf_threads_header(fp);
2878 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002879 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002880
Kan Liang91e467b2017-09-10 19:23:14 -07002881 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2882 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2883
2884 if (threads == NULL) {
2885 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2886 return 0;
2887 }
2888
2889 resort_rb__for_each_entry(nd, threads)
2890 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2891
2892 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002893 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002894 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002895}
2896
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002897static int trace__set_duration(const struct option *opt, const char *str,
2898 int unset __maybe_unused)
2899{
2900 struct trace *trace = opt->value;
2901
2902 trace->duration_filter = atof(str);
2903 return 0;
2904}
2905
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002906static int trace__set_filter_pids(const struct option *opt, const char *str,
2907 int unset __maybe_unused)
2908{
2909 int ret = -1;
2910 size_t i;
2911 struct trace *trace = opt->value;
2912 /*
2913 * FIXME: introduce a intarray class, plain parse csv and create a
2914 * { int nr, int entries[] } struct...
2915 */
2916 struct intlist *list = intlist__new(str);
2917
2918 if (list == NULL)
2919 return -1;
2920
2921 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2922 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2923
2924 if (trace->filter_pids.entries == NULL)
2925 goto out;
2926
2927 trace->filter_pids.entries[0] = getpid();
2928
2929 for (i = 1; i < trace->filter_pids.nr; ++i)
2930 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2931
2932 intlist__delete(list);
2933 ret = 0;
2934out:
2935 return ret;
2936}
2937
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002938static int trace__open_output(struct trace *trace, const char *filename)
2939{
2940 struct stat st;
2941
2942 if (!stat(filename, &st) && st.st_size) {
2943 char oldname[PATH_MAX];
2944
2945 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2946 unlink(oldname);
2947 rename(filename, oldname);
2948 }
2949
2950 trace->output = fopen(filename, "w");
2951
2952 return trace->output == NULL ? -errno : 0;
2953}
2954
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002955static int parse_pagefaults(const struct option *opt, const char *str,
2956 int unset __maybe_unused)
2957{
2958 int *trace_pgfaults = opt->value;
2959
2960 if (strcmp(str, "all") == 0)
2961 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2962 else if (strcmp(str, "maj") == 0)
2963 *trace_pgfaults |= TRACE_PFMAJ;
2964 else if (strcmp(str, "min") == 0)
2965 *trace_pgfaults |= TRACE_PFMIN;
2966 else
2967 return -1;
2968
2969 return 0;
2970}
2971
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002972static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2973{
2974 struct perf_evsel *evsel;
2975
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002976 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002977 evsel->handler = handler;
2978}
2979
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002980/*
2981 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2982 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2983 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2984 *
2985 * It'd be better to introduce a parse_options() variant that would return a
2986 * list with the terms it didn't match to an event...
2987 */
2988static int trace__parse_events_option(const struct option *opt, const char *str,
2989 int unset __maybe_unused)
2990{
2991 struct trace *trace = (struct trace *)opt->value;
2992 const char *s = str;
2993 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002994 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002995 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2996 char group_name[PATH_MAX];
2997
2998 if (strace_groups_dir == NULL)
2999 return -1;
3000
3001 if (*s == '!') {
3002 ++s;
3003 trace->not_ev_qualifier = true;
3004 }
3005
3006 while (1) {
3007 if ((sep = strchr(s, ',')) != NULL)
3008 *sep = '\0';
3009
3010 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003011 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3012 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003013 list = 1;
3014 } else {
3015 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3016 if (access(group_name, R_OK) == 0)
3017 list = 1;
3018 }
3019
3020 if (lists[list]) {
3021 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3022 } else {
3023 lists[list] = malloc(len);
3024 if (lists[list] == NULL)
3025 goto out;
3026 strcpy(lists[list], s);
3027 }
3028
3029 if (!sep)
3030 break;
3031
3032 *sep = ',';
3033 s = sep + 1;
3034 }
3035
3036 if (lists[1] != NULL) {
3037 struct strlist_config slist_config = {
3038 .dirname = strace_groups_dir,
3039 };
3040
3041 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3042 if (trace->ev_qualifier == NULL) {
3043 fputs("Not enough memory to parse event qualifier", trace->output);
3044 goto out;
3045 }
3046
3047 if (trace__validate_ev_qualifier(trace))
3048 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003049 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003050 }
3051
3052 err = 0;
3053
3054 if (lists[0]) {
3055 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3056 "event selector. use 'perf list' to list available events",
3057 parse_events_option);
3058 err = parse_events_option(&o, lists[0], 0);
3059 }
3060out:
3061 if (sep)
3062 *sep = ',';
3063
3064 return err;
3065}
3066
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003067static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3068{
3069 struct trace *trace = opt->value;
3070
3071 if (!list_empty(&trace->evlist->entries))
3072 return parse_cgroups(opt, str, unset);
3073
3074 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3075
3076 return 0;
3077}
3078
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003079int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003080{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003081 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003082 "perf trace [<options>] [<command>]",
3083 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003084 "perf trace record [<options>] [<command>]",
3085 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003086 NULL
3087 };
3088 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003089 .syscalls = {
3090 . max = -1,
3091 },
3092 .opts = {
3093 .target = {
3094 .uid = UINT_MAX,
3095 .uses_mmap = true,
3096 },
3097 .user_freq = UINT_MAX,
3098 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003099 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003100 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003101 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003102 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003103 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003104 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003105 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003106 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003107 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003108 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003109 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003110 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003111 OPT_CALLBACK('e', "event", &trace, "event",
3112 "event/syscall selector. use 'perf list' to list available events",
3113 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003114 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3115 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003116 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003117 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3118 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003119 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003120 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003121 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3122 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003123 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003124 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003125 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3126 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003127 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003128 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003129 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003130 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003131 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003132 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003133 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3134 "number of mmap data pages",
3135 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003136 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003137 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003138 OPT_CALLBACK(0, "duration", &trace, "float",
3139 "show only events with duration > N.M ms",
3140 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003141 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003142 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003143 OPT_BOOLEAN('T', "time", &trace.full_time,
3144 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003145 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3146 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003147 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3148 "Show only syscall summary with statistics"),
3149 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3150 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003151 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3152 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003153 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003154 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003155 OPT_CALLBACK(0, "call-graph", &trace.opts,
3156 "record_mode[,record_size]", record_callchain_help,
3157 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003158 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3159 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003160 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3161 "Set the minimum stack depth when parsing the callchain, "
3162 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003163 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3164 "Set the maximum stack depth when parsing the callchain, "
3165 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003166 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003167 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3168 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003169 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3170 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003171 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3172 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003173 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3174 "ms to wait before starting measurement after program "
3175 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003176 OPT_END()
3177 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003178 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003179 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003180 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003181 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003182 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003183
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003184 signal(SIGSEGV, sighandler_dump_stack);
3185 signal(SIGFPE, sighandler_dump_stack);
3186
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003187 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003188 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003189
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003190 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003191 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003192 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003193 goto out;
3194 }
3195
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003196 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3197 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003198
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003199 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3200 usage_with_options_msg(trace_usage, trace_options,
3201 "cgroup monitoring only available in system-wide mode");
3202 }
3203
Wang Nand7888572016-04-08 15:07:24 +00003204 err = bpf__setup_stdout(trace.evlist);
3205 if (err) {
3206 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3207 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3208 goto out;
3209 }
3210
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003211 err = -1;
3212
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003213 if (trace.trace_pgfaults) {
3214 trace.opts.sample_address = true;
3215 trace.opts.sample_time = true;
3216 }
3217
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003218 if (trace.opts.mmap_pages == UINT_MAX)
3219 mmap_pages_user_set = false;
3220
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003221 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003222 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003223 max_stack_user_set = false;
3224 }
3225
3226#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003227 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003228 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003229 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003230#endif
3231
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003232 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003233 if (!mmap_pages_user_set && geteuid() == 0)
3234 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3235
Milian Wolff566a0882016-04-08 13:34:15 +02003236 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003237 }
Milian Wolff566a0882016-04-08 13:34:15 +02003238
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003239 if (trace.evlist->nr_entries > 0)
3240 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3241
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003242 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3243 return trace__record(&trace, argc-1, &argv[1]);
3244
3245 /* summary_only implies summary option, but don't overwrite summary if set */
3246 if (trace.summary_only)
3247 trace.summary = trace.summary_only;
3248
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003249 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3250 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003251 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003252 }
3253
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003254 if (output_name != NULL) {
3255 err = trace__open_output(&trace, output_name);
3256 if (err < 0) {
3257 perror("failed to create output file");
3258 goto out;
3259 }
3260 }
3261
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003262 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003263 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003264 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003265 fprintf(trace.output, "%s", bf);
3266 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003267 }
3268
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003269 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003270 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003271 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003272 fprintf(trace.output, "%s", bf);
3273 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003274 }
3275
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003276 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003277 trace.opts.target.system_wide = true;
3278
David Ahern6810fc92013-08-28 22:29:52 -06003279 if (input_name)
3280 err = trace__replay(&trace);
3281 else
3282 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003283
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003284out_close:
3285 if (output_name != NULL)
3286 fclose(trace.output);
3287out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003288 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003289}