blob: 039f94467968a9f2fb649ec026a547dccf4c54e4 [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
159static int tp_field__init_uint(struct tp_field *field,
160 struct format_field *format_field,
161 bool needs_swap)
162{
163 field->offset = format_field->offset;
164
165 switch (format_field->size) {
166 case 1:
167 field->integer = tp_field__u8;
168 break;
169 case 2:
170 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
171 break;
172 case 4:
173 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
174 break;
175 case 8:
176 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
177 break;
178 default:
179 return -1;
180 }
181
182 return 0;
183}
184
185static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
186{
187 return sample->raw_data + field->offset;
188}
189
190static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
191{
192 field->offset = format_field->offset;
193 field->pointer = tp_field__ptr;
194 return 0;
195}
196
197struct syscall_tp {
198 struct tp_field id;
199 union {
200 struct tp_field args, ret;
201 };
202};
203
204static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
205 struct tp_field *field,
206 const char *name)
207{
208 struct format_field *format_field = perf_evsel__field(evsel, name);
209
210 if (format_field == NULL)
211 return -1;
212
213 return tp_field__init_uint(field, format_field, evsel->needs_swap);
214}
215
216#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
217 ({ struct syscall_tp *sc = evsel->priv;\
218 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
219
220static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
221 struct tp_field *field,
222 const char *name)
223{
224 struct format_field *format_field = perf_evsel__field(evsel, name);
225
226 if (format_field == NULL)
227 return -1;
228
229 return tp_field__init_ptr(field, format_field);
230}
231
232#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
233 ({ struct syscall_tp *sc = evsel->priv;\
234 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
235
236static void perf_evsel__delete_priv(struct perf_evsel *evsel)
237{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300238 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300239 perf_evsel__delete(evsel);
240}
241
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300242static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler)
Namhyung Kim96695d42013-11-12 08:51:45 -0300243{
244 evsel->priv = malloc(sizeof(struct syscall_tp));
245 if (evsel->priv != NULL) {
246 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
247 goto out_delete;
248
249 evsel->handler = handler;
250 return 0;
251 }
252
253 return -ENOMEM;
254
255out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300256 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300257 return -ENOENT;
258}
259
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300260static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300261{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300262 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300263
David Ahern9aca7f12013-12-04 19:41:39 -0700264 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200265 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700266 evsel = perf_evsel__newtp("syscalls", direction);
267
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200268 if (IS_ERR(evsel))
269 return NULL;
270
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300271 if (perf_evsel__init_raw_syscall_tp(evsel, handler))
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200272 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300273
274 return evsel;
275
276out_delete:
277 perf_evsel__delete_priv(evsel);
278 return NULL;
279}
280
281#define perf_evsel__sc_tp_uint(evsel, name, sample) \
282 ({ struct syscall_tp *fields = evsel->priv; \
283 fields->name.integer(&fields->name, sample); })
284
285#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
286 ({ struct syscall_tp *fields = evsel->priv; \
287 fields->name.pointer(&fields->name, sample); })
288
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300289size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
290{
291 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300292
Arnaldo Carvalho de Melobc972ad2018-07-26 15:30:33 -0300293 if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL)
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300294 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300295
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300296 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300297}
298
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300299static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
300 const char *intfmt,
301 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300303 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300304}
305
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300306static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
307 struct syscall_arg *arg)
308{
309 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
310}
311
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300312#define SCA_STRARRAY syscall_arg__scnprintf_strarray
313
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300314struct strarrays {
315 int nr_entries;
316 struct strarray **entries;
317};
318
319#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
320 .nr_entries = ARRAY_SIZE(array), \
321 .entries = array, \
322}
323
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300324size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
325 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300326{
327 struct strarrays *sas = arg->parm;
328 int i;
329
330 for (i = 0; i < sas->nr_entries; ++i) {
331 struct strarray *sa = sas->entries[i];
332 int idx = arg->val - sa->offset;
333
334 if (idx >= 0 && idx < sa->nr_entries) {
335 if (sa->entries[idx] == NULL)
336 break;
337 return scnprintf(bf, size, "%s", sa->entries[idx]);
338 }
339 }
340
341 return scnprintf(bf, size, "%d", arg->val);
342}
343
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300344#ifndef AT_FDCWD
345#define AT_FDCWD -100
346#endif
347
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300348static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
349 struct syscall_arg *arg)
350{
351 int fd = arg->val;
352
353 if (fd == AT_FDCWD)
354 return scnprintf(bf, size, "CWD");
355
356 return syscall_arg__scnprintf_fd(bf, size, arg);
357}
358
359#define SCA_FDAT syscall_arg__scnprintf_fd_at
360
361static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
362 struct syscall_arg *arg);
363
364#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
365
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300366size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300367{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300368 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300369}
370
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300371size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300372{
373 return scnprintf(bf, size, "%d", arg->val);
374}
375
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300376size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
377{
378 return scnprintf(bf, size, "%ld", arg->val);
379}
380
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300381static const char *bpf_cmd[] = {
382 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
383 "MAP_GET_NEXT_KEY", "PROG_LOAD",
384};
385static DEFINE_STRARRAY(bpf_cmd);
386
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300387static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
388static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300389
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300390static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
391static DEFINE_STRARRAY(itimers);
392
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300393static const char *keyctl_options[] = {
394 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
395 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
396 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
397 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
398 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
399};
400static DEFINE_STRARRAY(keyctl_options);
401
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300402static const char *whences[] = { "SET", "CUR", "END",
403#ifdef SEEK_DATA
404"DATA",
405#endif
406#ifdef SEEK_HOLE
407"HOLE",
408#endif
409};
410static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300411
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300412static const char *fcntl_cmds[] = {
413 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300414 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
415 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
416 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300417};
418static DEFINE_STRARRAY(fcntl_cmds);
419
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300420static const char *fcntl_linux_specific_cmds[] = {
421 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
422 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300423 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300424};
425
426static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
427
428static struct strarray *fcntl_cmds_arrays[] = {
429 &strarray__fcntl_cmds,
430 &strarray__fcntl_linux_specific_cmds,
431};
432
433static DEFINE_STRARRAYS(fcntl_cmds_arrays);
434
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300435static const char *rlimit_resources[] = {
436 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
437 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
438 "RTTIME",
439};
440static DEFINE_STRARRAY(rlimit_resources);
441
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300442static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
443static DEFINE_STRARRAY(sighow);
444
David Ahern4f8c1b72013-09-22 19:45:00 -0600445static const char *clockid[] = {
446 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300447 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
448 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600449};
450static DEFINE_STRARRAY(clockid);
451
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300452static const char *socket_families[] = {
453 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
454 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
455 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
456 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
457 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
458 "ALG", "NFC", "VSOCK",
459};
460static DEFINE_STRARRAY(socket_families);
461
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300462static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
463 struct syscall_arg *arg)
464{
465 size_t printed = 0;
466 int mode = arg->val;
467
468 if (mode == F_OK) /* 0 */
469 return scnprintf(bf, size, "F");
470#define P_MODE(n) \
471 if (mode & n##_OK) { \
472 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
473 mode &= ~n##_OK; \
474 }
475
476 P_MODE(R);
477 P_MODE(W);
478 P_MODE(X);
479#undef P_MODE
480
481 if (mode)
482 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
483
484 return printed;
485}
486
487#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
488
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300489static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
490 struct syscall_arg *arg);
491
492#define SCA_FILENAME syscall_arg__scnprintf_filename
493
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300494static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
495 struct syscall_arg *arg)
496{
497 int printed = 0, flags = arg->val;
498
499#define P_FLAG(n) \
500 if (flags & O_##n) { \
501 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
502 flags &= ~O_##n; \
503 }
504
505 P_FLAG(CLOEXEC);
506 P_FLAG(NONBLOCK);
507#undef P_FLAG
508
509 if (flags)
510 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
511
512 return printed;
513}
514
515#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
516
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300517#ifndef GRND_NONBLOCK
518#define GRND_NONBLOCK 0x0001
519#endif
520#ifndef GRND_RANDOM
521#define GRND_RANDOM 0x0002
522#endif
523
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300524static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
525 struct syscall_arg *arg)
526{
527 int printed = 0, flags = arg->val;
528
529#define P_FLAG(n) \
530 if (flags & GRND_##n) { \
531 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
532 flags &= ~GRND_##n; \
533 }
534
535 P_FLAG(RANDOM);
536 P_FLAG(NONBLOCK);
537#undef P_FLAG
538
539 if (flags)
540 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
541
542 return printed;
543}
544
545#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
546
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300547#define STRARRAY(name, array) \
548 { .scnprintf = SCA_STRARRAY, \
549 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300550
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +0100551#include "trace/beauty/arch_errno_names.c"
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300552#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300553#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300554#include "trace/beauty/futex_val3.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300555#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300556#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300557#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300558#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300559#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300560#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300561#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300562#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300563#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300564#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300565#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300566
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300567struct syscall_arg_fmt {
568 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
569 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300570 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300571 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300572};
573
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300574static struct syscall_fmt {
575 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300576 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300577 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300578 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300579 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300580 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300581 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300582} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300583 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300584 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300585 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300586 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300587 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300588 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300589 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300590 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300591 { .name = "clone", .errpid = true, .nr_args = 5,
592 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
593 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
594 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
595 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
596 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300597 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300598 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300599 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300600 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300601 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300602 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300603 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300604 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300605 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300606 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300607 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300608 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300609 .parm = &strarrays__fcntl_cmds_arrays,
610 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300611 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300612 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300613 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300614 { .name = "fstat", .alias = "newfstat", },
615 { .name = "fstatat", .alias = "newfstatat", },
616 { .name = "futex",
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300617 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
618 [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300619 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300620 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300621 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300623 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300624 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300625 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300626 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300627 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300628 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300629 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo2d1073d2018-01-09 12:03:47 -0300630 { .name = "gettid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300631 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300632 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300633#if defined(__i386__) || defined(__x86_64__)
634/*
635 * FIXME: Make this available to all arches.
636 */
Arnaldo Carvalho de Melo1cc47f22017-07-31 13:20:14 -0300637 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300638 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300639#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300640 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300641#endif
Arnaldo Carvalho de Melo1de30382017-10-31 11:32:23 -0300642 { .name = "kcmp", .nr_args = 5,
643 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
644 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
645 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
646 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
647 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300648 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300649 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300650 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300651 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300652 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300654 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300655 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300656 { .name = "lstat", .alias = "newlstat", },
657 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300658 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
659 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300660 { .name = "mkdirat",
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 = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300663 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300664 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300665 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300666 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300667 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300668 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200669/* The standard mmap maps to old_mmap on s390x */
670#if defined(__s390x__)
671 .alias = "old_mmap",
672#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300673 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
674 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
675 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300676 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300677 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
678 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300679 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300680 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300681 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
683 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
684 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300685 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300686 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300687 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300688 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300689 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300690 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300691 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300692 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300693 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300694 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300695 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300696 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
697 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300698 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300699 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
700 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300701 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300702 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
703 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
704 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300705 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300706 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300707 { .name = "pkey_alloc",
708 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
709 { .name = "pkey_free",
710 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
711 { .name = "pkey_mprotect",
712 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
713 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
714 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "poll", .timeout = true, },
716 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300717 { .name = "prctl", .alias = "arch_prctl",
718 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
719 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
720 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300721 { .name = "pread", .alias = "pread64", },
722 { .name = "preadv", .alias = "pread", },
723 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300724 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "pwrite", .alias = "pwrite64", },
726 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300727 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300728 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300729 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300730 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300731 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300732 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300733 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300734 { .name = "renameat",
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 = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300737 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300738 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300745 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300746 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300747 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
748 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "select", .timeout = true, },
750 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300756 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300757 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300758 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300759 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300760 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300761 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300762 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300763 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
764 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300765 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300766 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300767 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
768 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300769 { .name = "stat", .alias = "newstat", },
770 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300771 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
772 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
773 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300774 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300775 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300776 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300777 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300778 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300779 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300780 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300781 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300782 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300783 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300784 { .name = "uname", .alias = "newuname", },
785 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300786 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300787 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300788 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300789 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300790 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300791 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300792 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300793};
794
795static int syscall_fmt__cmp(const void *name, const void *fmtp)
796{
797 const struct syscall_fmt *fmt = fmtp;
798 return strcmp(name, fmt->name);
799}
800
801static struct syscall_fmt *syscall_fmt__find(const char *name)
802{
803 const int nmemb = ARRAY_SIZE(syscall_fmts);
804 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
805}
806
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300807/*
808 * is_exit: is this "exit" or "exit_group"?
809 * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
810 */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300811struct syscall {
812 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300813 int nr_args;
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300814 bool is_exit;
815 bool is_open;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300816 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817 const char *name;
818 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300819 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300820};
821
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300822/*
823 * We need to have this 'calculated' boolean because in some cases we really
824 * don't know what is the duration of a syscall, for instance, when we start
825 * a session and some threads are waiting for a syscall to finish, say 'poll',
826 * in which case all we can do is to print "( ? ) for duration and for the
827 * start timestamp.
828 */
829static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200830{
831 double duration = (double)t / NSEC_PER_MSEC;
832 size_t printed = fprintf(fp, "(");
833
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300834 if (!calculated)
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -0300835 printed += fprintf(fp, " ");
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300836 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200837 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
838 else if (duration >= 0.01)
839 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
840 else
841 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300842 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200843}
844
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300845/**
846 * filename.ptr: The filename char pointer that will be vfs_getname'd
847 * filename.entry_str_pos: Where to insert the string translated from
848 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300849 * ret_scnprintf: syscall args may set this to a different syscall return
850 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300851 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300852struct thread_trace {
853 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300854 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300855 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400856 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300857 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300858 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300859 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300860 struct {
861 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300862 short int entry_str_pos;
863 bool pending_open;
864 unsigned int namelen;
865 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300866 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300867 struct {
868 int max;
869 char **table;
870 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600871
872 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300873};
874
875static struct thread_trace *thread_trace__new(void)
876{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300877 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
878
879 if (ttrace)
880 ttrace->paths.max = -1;
881
David Ahernbf2575c2013-10-08 21:26:53 -0600882 ttrace->syscall_stats = intlist__new(NULL);
883
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300884 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300885}
886
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300887static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300888{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300889 struct thread_trace *ttrace;
890
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300891 if (thread == NULL)
892 goto fail;
893
Namhyung Kim89dceb22014-10-06 09:46:03 +0900894 if (thread__priv(thread) == NULL)
895 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300896
Namhyung Kim89dceb22014-10-06 09:46:03 +0900897 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300898 goto fail;
899
Namhyung Kim89dceb22014-10-06 09:46:03 +0900900 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300901 ++ttrace->nr_events;
902
903 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300904fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300905 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300906 "WARNING: not enough memory, dropping samples!\n");
907 return NULL;
908}
909
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300910
911void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300912 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300913{
914 struct thread_trace *ttrace = thread__priv(arg->thread);
915
916 ttrace->ret_scnprintf = ret_scnprintf;
917}
918
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400919#define TRACE_PFMAJ (1 << 0)
920#define TRACE_PFMIN (1 << 1)
921
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300922static const size_t trace__entry_str_size = 2048;
923
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300924static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300925{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900926 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300927
928 if (fd > ttrace->paths.max) {
929 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
930
931 if (npath == NULL)
932 return -1;
933
934 if (ttrace->paths.max != -1) {
935 memset(npath + ttrace->paths.max + 1, 0,
936 (fd - ttrace->paths.max) * sizeof(char *));
937 } else {
938 memset(npath, 0, (fd + 1) * sizeof(char *));
939 }
940
941 ttrace->paths.table = npath;
942 ttrace->paths.max = fd;
943 }
944
945 ttrace->paths.table[fd] = strdup(pathname);
946
947 return ttrace->paths.table[fd] != NULL ? 0 : -1;
948}
949
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300950static int thread__read_fd_path(struct thread *thread, int fd)
951{
952 char linkname[PATH_MAX], pathname[PATH_MAX];
953 struct stat st;
954 int ret;
955
956 if (thread->pid_ == thread->tid) {
957 scnprintf(linkname, sizeof(linkname),
958 "/proc/%d/fd/%d", thread->pid_, fd);
959 } else {
960 scnprintf(linkname, sizeof(linkname),
961 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
962 }
963
964 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
965 return -1;
966
967 ret = readlink(linkname, pathname, sizeof(pathname));
968
969 if (ret < 0 || ret > st.st_size)
970 return -1;
971
972 pathname[ret] = '\0';
973 return trace__set_fd_pathname(thread, fd, pathname);
974}
975
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300976static const char *thread__fd_path(struct thread *thread, int fd,
977 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300978{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900979 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300980
981 if (ttrace == NULL)
982 return NULL;
983
984 if (fd < 0)
985 return NULL;
986
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300987 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300988 if (!trace->live)
989 return NULL;
990 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300991 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300992 return NULL;
993 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994
995 return ttrace->paths.table[fd];
996}
997
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -0300998size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300999{
1000 int fd = arg->val;
1001 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001002 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001003
1004 if (path)
1005 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1006
1007 return printed;
1008}
1009
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -03001010size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1011{
1012 size_t printed = scnprintf(bf, size, "%d", fd);
1013 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1014
1015 if (thread) {
1016 const char *path = thread__fd_path(thread, fd, trace);
1017
1018 if (path)
1019 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1020
1021 thread__put(thread);
1022 }
1023
1024 return printed;
1025}
1026
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1028 struct syscall_arg *arg)
1029{
1030 int fd = arg->val;
1031 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001032 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001033
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001034 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1035 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001036
1037 return printed;
1038}
1039
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001040static void thread__set_filename_pos(struct thread *thread, const char *bf,
1041 unsigned long ptr)
1042{
1043 struct thread_trace *ttrace = thread__priv(thread);
1044
1045 ttrace->filename.ptr = ptr;
1046 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1047}
1048
1049static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1050 struct syscall_arg *arg)
1051{
1052 unsigned long ptr = arg->val;
1053
1054 if (!arg->trace->vfs_getname)
1055 return scnprintf(bf, size, "%#x", ptr);
1056
1057 thread__set_filename_pos(arg->thread, bf, ptr);
1058 return 0;
1059}
1060
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001061static bool trace__filter_duration(struct trace *trace, double t)
1062{
1063 return t < (trace->duration_filter * NSEC_PER_MSEC);
1064}
1065
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001066static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001067{
1068 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1069
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001070 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001071}
1072
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001073/*
1074 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1075 * using ttrace->entry_time for a thread that receives a sys_exit without
1076 * first having received a sys_enter ("poll" issued before tracing session
1077 * starts, lost sys_enter exit due to ring buffer overflow).
1078 */
1079static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1080{
1081 if (tstamp > 0)
1082 return __trace__fprintf_tstamp(trace, tstamp, fp);
1083
1084 return fprintf(fp, " ? ");
1085}
1086
Namhyung Kimf15eb532012-10-05 14:02:16 +09001087static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001088static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001089
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001090static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001091{
1092 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001093 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001094}
1095
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001096static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001097 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098{
1099 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001100 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001101
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001102 if (trace->multiple_threads) {
1103 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001104 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001105 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001106 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001107
1108 return printed;
1109}
1110
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001111static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001112 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113{
1114 int ret = 0;
1115
1116 switch (event->header.type) {
1117 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001118 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001119 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001120 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001121 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001123 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001124 break;
1125 }
1126
1127 return ret;
1128}
1129
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001130static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001132 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001133 struct machine *machine)
1134{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001135 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001136 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137}
1138
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001139static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1140{
1141 struct machine *machine = vmachine;
1142
1143 if (machine->kptr_restrict_warned)
1144 return NULL;
1145
1146 if (symbol_conf.kptr_restrict) {
1147 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1148 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1149 "Kernel samples will not be resolved.\n");
1150 machine->kptr_restrict_warned = true;
1151 return NULL;
1152 }
1153
1154 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1155}
1156
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1158{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001159 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001160
1161 if (err)
1162 return err;
1163
David Ahern8fb598e2013-09-28 13:13:00 -06001164 trace->host = machine__new_host();
1165 if (trace->host == NULL)
1166 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001167
Andrei Vagincbd5c172017-11-07 16:22:46 -08001168 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1169 if (err < 0)
1170 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001171
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001172 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001173 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001174 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001175out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001176 if (err)
1177 symbol__exit();
1178
1179 return err;
1180}
1181
Andrei Vagin33974a42017-11-07 16:22:45 -08001182static void trace__symbols__exit(struct trace *trace)
1183{
1184 machine__exit(trace->host);
1185 trace->host = NULL;
1186
1187 symbol__exit();
1188}
1189
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001190static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1191{
1192 int idx;
1193
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001194 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1195 nr_args = sc->fmt->nr_args;
1196
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001197 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1198 if (sc->arg_fmt == NULL)
1199 return -1;
1200
1201 for (idx = 0; idx < nr_args; ++idx) {
1202 if (sc->fmt)
1203 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1204 }
1205
1206 sc->nr_args = nr_args;
1207 return 0;
1208}
1209
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001210static int syscall__set_arg_fmts(struct syscall *sc)
1211{
1212 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001213 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001214
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001215 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001216 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1217 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001218
1219 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001220 (strcmp(field->name, "filename") == 0 ||
1221 strcmp(field->name, "path") == 0 ||
1222 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001223 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001224 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001225 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001226 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001227 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001228 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001229 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001230 else if ((strcmp(field->type, "int") == 0 ||
1231 strcmp(field->type, "unsigned int") == 0 ||
1232 strcmp(field->type, "long") == 0) &&
1233 (len = strlen(field->name)) >= 2 &&
1234 strcmp(field->name + len - 2, "fd") == 0) {
1235 /*
1236 * /sys/kernel/tracing/events/syscalls/sys_enter*
1237 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1238 * 65 int
1239 * 23 unsigned int
1240 * 7 unsigned long
1241 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001242 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001243 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001244 }
1245
1246 return 0;
1247}
1248
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001249static int trace__read_syscall_info(struct trace *trace, int id)
1250{
1251 char tp_name[128];
1252 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001253 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001254
1255 if (name == NULL)
1256 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001257
1258 if (id > trace->syscalls.max) {
1259 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1260
1261 if (nsyscalls == NULL)
1262 return -1;
1263
1264 if (trace->syscalls.max != -1) {
1265 memset(nsyscalls + trace->syscalls.max + 1, 0,
1266 (id - trace->syscalls.max) * sizeof(*sc));
1267 } else {
1268 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1269 }
1270
1271 trace->syscalls.table = nsyscalls;
1272 trace->syscalls.max = id;
1273 }
1274
1275 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001276 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001277
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001278 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001279
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001280 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001281 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001282
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001283 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001284 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001285 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001286 }
1287
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001288 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1289 return -1;
1290
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001291 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001292 return -1;
1293
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001294 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001295 /*
1296 * We need to check and discard the first variable '__syscall_nr'
1297 * or 'nr' that mean the syscall number. It is needless here.
1298 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1299 */
1300 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001301 sc->args = sc->args->next;
1302 --sc->nr_args;
1303 }
1304
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001305 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001306 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001307
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001308 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001309}
1310
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001311static int trace__validate_ev_qualifier(struct trace *trace)
1312{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001313 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001314 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001315 struct str_node *pos;
1316
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001317 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1318 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1319 sizeof(trace->ev_qualifier_ids.entries[0]));
1320
1321 if (trace->ev_qualifier_ids.entries == NULL) {
1322 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1323 trace->output);
1324 err = -EINVAL;
1325 goto out;
1326 }
1327
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001328 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001329 i = 0;
1330
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001331 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001332 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001333 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001334
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001335 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001336 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1337 if (id >= 0)
1338 goto matches;
1339
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001340 if (err == 0) {
1341 fputs("Error:\tInvalid syscall ", trace->output);
1342 err = -EINVAL;
1343 } else {
1344 fputs(", ", trace->output);
1345 }
1346
1347 fputs(sc, trace->output);
1348 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001349matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001350 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001351 if (match_next == -1)
1352 continue;
1353
1354 while (1) {
1355 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1356 if (id < 0)
1357 break;
1358 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1359 void *entries;
1360
1361 nr_allocated += 8;
1362 entries = realloc(trace->ev_qualifier_ids.entries,
1363 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1364 if (entries == NULL) {
1365 err = -ENOMEM;
1366 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1367 goto out_free;
1368 }
1369 trace->ev_qualifier_ids.entries = entries;
1370 }
1371 trace->ev_qualifier_ids.nr++;
1372 trace->ev_qualifier_ids.entries[i++] = id;
1373 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001374 }
1375
1376 if (err < 0) {
1377 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1378 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001379out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001380 zfree(&trace->ev_qualifier_ids.entries);
1381 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001382 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001383out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001384 return err;
1385}
1386
David Ahern55d43bca2015-02-19 15:00:22 -05001387/*
1388 * args is to be interpreted as a series of longs but we need to handle
1389 * 8-byte unaligned accesses. args points to raw_data within the event
1390 * and raw_data is guaranteed to be 8-byte unaligned because it is
1391 * preceded by raw_size which is a u32. So we need to copy args to a temp
1392 * variable to read it. Most notably this avoids extended load instructions
1393 * on unaligned addresses
1394 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001395unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001396{
1397 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001398 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001399
1400 memcpy(&val, p, sizeof(val));
1401 return val;
1402}
1403
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001404static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1405 struct syscall_arg *arg)
1406{
1407 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1408 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1409
1410 return scnprintf(bf, size, "arg%d: ", arg->idx);
1411}
1412
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001413static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1414 struct syscall_arg *arg, unsigned long val)
1415{
1416 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1417 arg->val = val;
1418 if (sc->arg_fmt[arg->idx].parm)
1419 arg->parm = sc->arg_fmt[arg->idx].parm;
1420 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1421 }
1422 return scnprintf(bf, size, "%ld", val);
1423}
1424
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001425static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001426 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001427 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001428{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001429 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001430 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001431 u8 bit = 1;
1432 struct syscall_arg arg = {
1433 .args = args,
1434 .idx = 0,
1435 .mask = 0,
1436 .trace = trace,
1437 .thread = thread,
1438 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001439 struct thread_trace *ttrace = thread__priv(thread);
1440
1441 /*
1442 * Things like fcntl will set this in its 'cmd' formatter to pick the
1443 * right formatter for the return value (an fd? file flags?), which is
1444 * not needed for syscalls that always return a given type, say an fd.
1445 */
1446 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001447
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001448 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001449 struct format_field *field;
1450
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001451 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001452 field = field->next, ++arg.idx, bit <<= 1) {
1453 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001454 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001455
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001456 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001457
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001458 /*
1459 * Suppress this argument if its value is zero and
1460 * and we don't have a string associated in an
1461 * strarray for it.
1462 */
David Ahern55d43bca2015-02-19 15:00:22 -05001463 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001464 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001465 (sc->arg_fmt[arg.idx].show_zero ||
1466 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001467 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1468 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001469 continue;
1470
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001471 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001472 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001473 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001474 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001475 } else if (IS_ERR(sc->tp_format)) {
1476 /*
1477 * If we managed to read the tracepoint /format file, then we
1478 * may end up not having any args, like with gettid(), so only
1479 * print the raw args when we didn't manage to read it.
1480 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001481 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001482 if (arg.mask & bit)
1483 goto next_arg;
1484 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001485 if (printed)
1486 printed += scnprintf(bf + printed, size - printed, ", ");
1487 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001488 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1489next_arg:
1490 ++arg.idx;
1491 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001492 }
1493 }
1494
1495 return printed;
1496}
1497
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001498typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001499 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001500 struct perf_sample *sample);
1501
1502static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001503 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001504{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001505
1506 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001507
1508 /*
1509 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1510 * before that, leaving at a higher verbosity level till that is
1511 * explained. Reproduced with plain ftrace with:
1512 *
1513 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1514 * grep "NR -1 " /t/trace_pipe
1515 *
1516 * After generating some load on the machine.
1517 */
1518 if (verbose > 1) {
1519 static u64 n;
1520 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1521 id, perf_evsel__name(evsel), ++n);
1522 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001523 return NULL;
1524 }
1525
1526 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1527 trace__read_syscall_info(trace, id))
1528 goto out_cant_read;
1529
1530 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1531 goto out_cant_read;
1532
1533 return &trace->syscalls.table[id];
1534
1535out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001536 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001537 fprintf(trace->output, "Problems reading syscall %d", id);
1538 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1539 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1540 fputs(" information\n", trace->output);
1541 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001542 return NULL;
1543}
1544
David Ahernbf2575c2013-10-08 21:26:53 -06001545static void thread__update_stats(struct thread_trace *ttrace,
1546 int id, struct perf_sample *sample)
1547{
1548 struct int_node *inode;
1549 struct stats *stats;
1550 u64 duration = 0;
1551
1552 inode = intlist__findnew(ttrace->syscall_stats, id);
1553 if (inode == NULL)
1554 return;
1555
1556 stats = inode->priv;
1557 if (stats == NULL) {
1558 stats = malloc(sizeof(struct stats));
1559 if (stats == NULL)
1560 return;
1561 init_stats(stats);
1562 inode->priv = stats;
1563 }
1564
1565 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1566 duration = sample->time - ttrace->entry_time;
1567
1568 update_stats(stats, duration);
1569}
1570
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001571static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001572{
1573 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001574 size_t printed;
1575
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001576 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001577 return 0;
1578
1579 ttrace = thread__priv(trace->current);
1580
1581 if (!ttrace->entry_pending)
1582 return 0;
1583
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001584 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001585 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1586 ttrace->entry_pending = false;
1587
1588 return printed;
1589}
1590
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001591static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1592 struct perf_sample *sample, struct thread *thread)
1593{
1594 int printed = 0;
1595
1596 if (trace->print_sample) {
1597 double ts = (double)sample->time / NSEC_PER_MSEC;
1598
1599 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1600 perf_evsel__name(evsel), ts,
1601 thread__comm_str(thread),
1602 sample->pid, sample->tid, sample->cpu);
1603 }
1604
1605 return printed;
1606}
1607
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001608static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001609 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001610 struct perf_sample *sample)
1611{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001612 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001613 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001614 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001615 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001616 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001617 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001618 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001619
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001620 if (sc == NULL)
1621 return -1;
1622
David Ahern8fb598e2013-09-28 13:13:00 -06001623 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001624 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001625 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001626 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001627
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001628 trace__fprintf_sample(trace, evsel, sample, thread);
1629
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001630 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001631
1632 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001633 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001634 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001635 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001636 }
1637
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001638 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001639 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001640
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001641 ttrace->entry_time = sample->time;
1642 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001643 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001644
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001645 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001646 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001647
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001648 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001649 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001650 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001651 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001652 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001653 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001654 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001655 /* See trace__vfs_getname & trace__sys_exit */
1656 ttrace->filename.pending_open = false;
1657 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001658
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001659 if (trace->current != thread) {
1660 thread__put(trace->current);
1661 trace->current = thread__get(thread);
1662 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001663 err = 0;
1664out_put:
1665 thread__put(thread);
1666 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001667}
1668
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001669static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1670 struct perf_sample *sample)
1671{
1672 struct format_field *field = perf_evsel__field(evsel, "__syscall_nr");
1673 struct thread_trace *ttrace;
1674 struct thread *thread;
1675 struct syscall *sc;
1676 char msg[1024];
1677 int id, err = -1;
1678 void *args;
1679
1680 if (field == NULL)
1681 return -1;
1682
1683 id = format_field__intval(field, sample, evsel->needs_swap);
1684 sc = trace__syscall_info(trace, evsel, id);
1685
1686 if (sc == NULL)
1687 return -1;
1688
1689 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1690 ttrace = thread__trace(thread, trace->output);
1691 /*
1692 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1693 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1694 */
1695 if (ttrace == NULL)
1696 goto out_put;
1697
1698 args = sample->raw_data + field->offset + sizeof(u64); /* skip __syscall_nr, there is where args are */
1699 syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread);
1700 fprintf(trace->output, "%s", msg);
1701 err = 0;
1702out_put:
1703 thread__put(thread);
1704 return err;
1705}
1706
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001707static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1708 struct perf_sample *sample,
1709 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001710{
1711 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301712 int max_stack = evsel->attr.sample_max_stack ?
1713 evsel->attr.sample_max_stack :
1714 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001715
1716 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301717 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001718 return -1;
1719
1720 return 0;
1721}
1722
1723static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1724{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001725 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001726 const unsigned int print_opts = EVSEL__PRINT_SYM |
1727 EVSEL__PRINT_DSO |
1728 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001729
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001730 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001731}
1732
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001733static const char *errno_to_name(struct perf_evsel *evsel, int err)
1734{
1735 struct perf_env *env = perf_evsel__env(evsel);
1736 const char *arch_name = perf_env__arch(env);
1737
1738 return arch_syscalls__strerrno(arch_name, err);
1739}
1740
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001741static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001742 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001743 struct perf_sample *sample)
1744{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001745 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001746 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001747 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001748 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001749 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001750 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001751 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001752
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001753 if (sc == NULL)
1754 return -1;
1755
David Ahern8fb598e2013-09-28 13:13:00 -06001756 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001757 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001758 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001759 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001760
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001761 trace__fprintf_sample(trace, evsel, sample, thread);
1762
David Ahernbf2575c2013-10-08 21:26:53 -06001763 if (trace->summary)
1764 thread__update_stats(ttrace, id, sample);
1765
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001766 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001767
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001768 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001769 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1770 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001771 ++trace->stats.vfs_getname;
1772 }
1773
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001774 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001775 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001776 if (trace__filter_duration(trace, duration))
1777 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001778 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001779 } else if (trace->duration_filter)
1780 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001781
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001782 if (sample->callchain) {
1783 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1784 if (callchain_ret == 0) {
1785 if (callchain_cursor.nr < trace->min_stack)
1786 goto out;
1787 callchain_ret = 1;
1788 }
1789 }
1790
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001791 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001792 goto out;
1793
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001794 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001795
1796 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001797 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001798 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001799 fprintf(trace->output, " ... [");
1800 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1801 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001802 }
1803
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001804 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001805 if (ret < 0)
1806 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001807signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001808 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001809 } else if (ret < 0) {
1810errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001811 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001812 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001813 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001814
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001815 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001816 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001817 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001818 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001819 else if (ttrace->ret_scnprintf) {
1820 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001821 struct syscall_arg arg = {
1822 .val = ret,
1823 .thread = thread,
1824 .trace = trace,
1825 };
1826 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001827 ttrace->ret_scnprintf = NULL;
1828 fprintf(trace->output, ") = %s", bf);
1829 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001830 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001831 else if (sc->fmt->errpid) {
1832 struct thread *child = machine__find_thread(trace->host, ret, ret);
1833
1834 if (child != NULL) {
1835 fprintf(trace->output, ") = %ld", ret);
1836 if (child->comm_set)
1837 fprintf(trace->output, " (%s)", thread__comm_str(child));
1838 thread__put(child);
1839 }
1840 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001841 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001842
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001843 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001844
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001845 if (callchain_ret > 0)
1846 trace__fprintf_callchain(trace, sample);
1847 else if (callchain_ret < 0)
1848 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001849out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001850 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001851 err = 0;
1852out_put:
1853 thread__put(thread);
1854 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001855}
1856
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001857static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001858 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001859 struct perf_sample *sample)
1860{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001861 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1862 struct thread_trace *ttrace;
1863 size_t filename_len, entry_str_len, to_move;
1864 ssize_t remaining_space;
1865 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001866 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001867
1868 if (!thread)
1869 goto out;
1870
1871 ttrace = thread__priv(thread);
1872 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001873 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001874
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001875 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001876 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001877 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001878
1879 if (ttrace->filename.namelen < filename_len) {
1880 char *f = realloc(ttrace->filename.name, filename_len + 1);
1881
1882 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001883 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001884
1885 ttrace->filename.namelen = filename_len;
1886 ttrace->filename.name = f;
1887 }
1888
1889 strcpy(ttrace->filename.name, filename);
1890 ttrace->filename.pending_open = true;
1891
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001892 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001893 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001894
1895 entry_str_len = strlen(ttrace->entry_str);
1896 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1897 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001898 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001899
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001900 if (filename_len > (size_t)remaining_space) {
1901 filename += filename_len - remaining_space;
1902 filename_len = remaining_space;
1903 }
1904
1905 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1906 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1907 memmove(pos + filename_len, pos, to_move);
1908 memcpy(pos, filename, filename_len);
1909
1910 ttrace->filename.ptr = 0;
1911 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001912out_put:
1913 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001914out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001915 return 0;
1916}
1917
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001918static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001919 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001920 struct perf_sample *sample)
1921{
1922 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1923 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001924 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001925 sample->pid,
1926 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001927 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001928
1929 if (ttrace == NULL)
1930 goto out_dump;
1931
1932 ttrace->runtime_ms += runtime_ms;
1933 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001934out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001935 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001936 return 0;
1937
1938out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001939 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001940 evsel->name,
1941 perf_evsel__strval(evsel, sample, "comm"),
1942 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1943 runtime,
1944 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001945 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001946}
1947
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001948static int bpf_output__printer(enum binary_printer_ops op,
1949 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001950{
Wang Nan1d6c9402016-02-26 09:31:55 +00001951 unsigned char ch = (unsigned char)val;
1952
1953 switch (op) {
1954 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001955 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001956 case BINARY_PRINT_DATA_BEGIN:
1957 case BINARY_PRINT_LINE_BEGIN:
1958 case BINARY_PRINT_ADDR:
1959 case BINARY_PRINT_NUM_DATA:
1960 case BINARY_PRINT_NUM_PAD:
1961 case BINARY_PRINT_SEP:
1962 case BINARY_PRINT_CHAR_PAD:
1963 case BINARY_PRINT_LINE_END:
1964 case BINARY_PRINT_DATA_END:
1965 default:
1966 break;
1967 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001968
1969 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001970}
1971
1972static void bpf_output__fprintf(struct trace *trace,
1973 struct perf_sample *sample)
1974{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001975 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1976 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001977}
1978
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001979static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1980 union perf_event *event __maybe_unused,
1981 struct perf_sample *sample)
1982{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001983 int callchain_ret = 0;
1984
1985 if (sample->callchain) {
1986 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1987 if (callchain_ret == 0) {
1988 if (callchain_cursor.nr < trace->min_stack)
1989 goto out;
1990 callchain_ret = 1;
1991 }
1992 }
1993
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001994 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001995 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001996
1997 if (trace->trace_syscalls)
1998 fprintf(trace->output, "( ): ");
1999
2000 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002001
Wang Nan1d6c9402016-02-26 09:31:55 +00002002 if (perf_evsel__is_bpf_output(evsel)) {
2003 bpf_output__fprintf(trace, sample);
2004 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002005 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2006 trace__fprintf_sys_enter(trace, evsel, sample)) {
2007 event_format__fprintf(evsel->tp_format, sample->cpu,
2008 sample->raw_data, sample->raw_size,
2009 trace->output);
2010 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002011 }
2012
Changbin Du51125a22018-03-13 18:40:01 +08002013 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002014
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002015 if (callchain_ret > 0)
2016 trace__fprintf_callchain(trace, sample);
2017 else if (callchain_ret < 0)
2018 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2019out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002020 return 0;
2021}
2022
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002023static void print_location(FILE *f, struct perf_sample *sample,
2024 struct addr_location *al,
2025 bool print_dso, bool print_sym)
2026{
2027
Namhyung Kimbb963e12017-02-17 17:17:38 +09002028 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002029 fprintf(f, "%s@", al->map->dso->long_name);
2030
Namhyung Kimbb963e12017-02-17 17:17:38 +09002031 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002032 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002033 al->addr - al->sym->start);
2034 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002035 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002036 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002037 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002038}
2039
2040static int trace__pgfault(struct trace *trace,
2041 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002042 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002043 struct perf_sample *sample)
2044{
2045 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002046 struct addr_location al;
2047 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002048 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002049 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002050 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002051
2052 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002053
2054 if (sample->callchain) {
2055 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2056 if (callchain_ret == 0) {
2057 if (callchain_cursor.nr < trace->min_stack)
2058 goto out_put;
2059 callchain_ret = 1;
2060 }
2061 }
2062
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002063 ttrace = thread__trace(thread, trace->output);
2064 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002065 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002066
2067 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2068 ttrace->pfmaj++;
2069 else
2070 ttrace->pfmin++;
2071
2072 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002073 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002074
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002075 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002076
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002077 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002078
2079 fprintf(trace->output, "%sfault [",
2080 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2081 "maj" : "min");
2082
2083 print_location(trace->output, sample, &al, false, true);
2084
2085 fprintf(trace->output, "] => ");
2086
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002087 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002088
2089 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002090 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002091
2092 if (al.map)
2093 map_type = 'x';
2094 else
2095 map_type = '?';
2096 }
2097
2098 print_location(trace->output, sample, &al, true, false);
2099
2100 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002101
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002102 if (callchain_ret > 0)
2103 trace__fprintf_callchain(trace, sample);
2104 else if (callchain_ret < 0)
2105 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002106out:
2107 err = 0;
2108out_put:
2109 thread__put(thread);
2110 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002111}
2112
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002113static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002114 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002115 struct perf_sample *sample)
2116{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002117 /*
2118 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2119 * and don't use sample->time unconditionally, we may end up having
2120 * some other event in the future without PERF_SAMPLE_TIME for good
2121 * reason, i.e. we may not be interested in its timestamps, just in
2122 * it taking place, picking some piece of information when it
2123 * appears in our event stream (vfs_getname comes to mind).
2124 */
2125 if (trace->base_time == 0 && !trace->full_time &&
2126 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002127 trace->base_time = sample->time;
2128}
2129
David Ahern6810fc92013-08-28 22:29:52 -06002130static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002131 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002132 struct perf_sample *sample,
2133 struct perf_evsel *evsel,
2134 struct machine *machine __maybe_unused)
2135{
2136 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002137 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002138 int err = 0;
2139
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002140 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002141
David Ahernaa07df62016-11-25 09:29:52 -07002142 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2143 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002144 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002145
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002146 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002147
David Ahern31605652013-12-04 19:41:41 -07002148 if (handler) {
2149 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002150 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002151 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002152out:
2153 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002154 return err;
2155}
2156
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002157static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002158{
2159 unsigned int rec_argc, i, j;
2160 const char **rec_argv;
2161 const char * const record_args[] = {
2162 "record",
2163 "-R",
2164 "-m", "1024",
2165 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002166 };
2167
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002168 const char * const sc_args[] = { "-e", };
2169 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2170 const char * const majpf_args[] = { "-e", "major-faults" };
2171 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2172 const char * const minpf_args[] = { "-e", "minor-faults" };
2173 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2174
David Ahern9aca7f12013-12-04 19:41:39 -07002175 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002176 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2177 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002178 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2179
2180 if (rec_argv == NULL)
2181 return -ENOMEM;
2182
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002183 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002184 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002185 rec_argv[j++] = record_args[i];
2186
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002187 if (trace->trace_syscalls) {
2188 for (i = 0; i < sc_args_nr; i++)
2189 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002190
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002191 /* event string may be different for older kernels - e.g., RHEL6 */
2192 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2193 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2194 else if (is_valid_tracepoint("syscalls:sys_enter"))
2195 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2196 else {
2197 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002198 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002199 return -1;
2200 }
David Ahern9aca7f12013-12-04 19:41:39 -07002201 }
David Ahern9aca7f12013-12-04 19:41:39 -07002202
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002203 if (trace->trace_pgfaults & TRACE_PFMAJ)
2204 for (i = 0; i < majpf_args_nr; i++)
2205 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002206
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002207 if (trace->trace_pgfaults & TRACE_PFMIN)
2208 for (i = 0; i < minpf_args_nr; i++)
2209 rec_argv[j++] = minpf_args[i];
2210
2211 for (i = 0; i < (unsigned int)argc; i++)
2212 rec_argv[j++] = argv[i];
2213
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002214 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002215}
2216
David Ahernbf2575c2013-10-08 21:26:53 -06002217static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2218
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002219static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002220{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002221 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002222
2223 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002224 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002225
2226 if (perf_evsel__field(evsel, "pathname") == NULL) {
2227 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002228 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002229 }
2230
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002231 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002232 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002233 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002234}
2235
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002236static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002237{
2238 struct perf_evsel *evsel;
2239 struct perf_event_attr attr = {
2240 .type = PERF_TYPE_SOFTWARE,
2241 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002242 };
2243
2244 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002245 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002246
2247 event_attr_init(&attr);
2248
2249 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002250 if (evsel)
2251 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002252
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002253 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002254}
2255
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002256static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2257{
2258 const u32 type = event->header.type;
2259 struct perf_evsel *evsel;
2260
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002261 if (type != PERF_RECORD_SAMPLE) {
2262 trace__process_event(trace, trace->host, event, sample);
2263 return;
2264 }
2265
2266 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2267 if (evsel == NULL) {
2268 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2269 return;
2270 }
2271
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002272 trace__set_base_time(trace, evsel, sample);
2273
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002274 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2275 sample->raw_data == NULL) {
2276 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2277 perf_evsel__name(evsel), sample->tid,
2278 sample->cpu, sample->raw_size);
2279 } else {
2280 tracepoint_handler handler = evsel->handler;
2281 handler(trace, evsel, event, sample);
2282 }
2283}
2284
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002285static int trace__add_syscall_newtp(struct trace *trace)
2286{
2287 int ret = -1;
2288 struct perf_evlist *evlist = trace->evlist;
2289 struct perf_evsel *sys_enter, *sys_exit;
2290
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002291 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002292 if (sys_enter == NULL)
2293 goto out;
2294
2295 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2296 goto out_delete_sys_enter;
2297
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002298 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002299 if (sys_exit == NULL)
2300 goto out_delete_sys_enter;
2301
2302 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2303 goto out_delete_sys_exit;
2304
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002305 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2306 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2307
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002308 perf_evlist__add(evlist, sys_enter);
2309 perf_evlist__add(evlist, sys_exit);
2310
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002311 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002312 /*
2313 * We're interested only in the user space callchain
2314 * leading to the syscall, allow overriding that for
2315 * debugging reasons using --kernel_syscall_callchains
2316 */
2317 sys_exit->attr.exclude_callchain_kernel = 1;
2318 }
2319
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002320 trace->syscalls.events.sys_enter = sys_enter;
2321 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002322
2323 ret = 0;
2324out:
2325 return ret;
2326
2327out_delete_sys_exit:
2328 perf_evsel__delete_priv(sys_exit);
2329out_delete_sys_enter:
2330 perf_evsel__delete_priv(sys_enter);
2331 goto out;
2332}
2333
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002334static int trace__set_ev_qualifier_filter(struct trace *trace)
2335{
2336 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002337 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002338 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2339 trace->ev_qualifier_ids.nr,
2340 trace->ev_qualifier_ids.entries);
2341
2342 if (filter == NULL)
2343 goto out_enomem;
2344
Mathieu Poirier3541c032016-09-16 08:44:04 -06002345 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2346 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002347 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002348 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002349 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002350
2351 free(filter);
2352out:
2353 return err;
2354out_enomem:
2355 errno = ENOMEM;
2356 goto out;
2357}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002358
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002359static int trace__set_filter_loop_pids(struct trace *trace)
2360{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002361 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002362 pid_t pids[32] = {
2363 getpid(),
2364 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002365 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2366
2367 while (thread && nr < ARRAY_SIZE(pids)) {
2368 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2369
2370 if (parent == NULL)
2371 break;
2372
2373 if (!strcmp(thread__comm_str(parent), "sshd")) {
2374 pids[nr++] = parent->tid;
2375 break;
2376 }
2377 thread = parent;
2378 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002379
2380 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2381}
2382
Namhyung Kimf15eb532012-10-05 14:02:16 +09002383static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002384{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002385 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002386 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002387 int err = -1, i;
2388 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002389 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002390 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002391
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002392 trace->live = true;
2393
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002394 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002395 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002396
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002397 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002398 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002399
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002400 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2401 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2402 if (pgfault_maj == NULL)
2403 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002404 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002405 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002406 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002407
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002408 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2409 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2410 if (pgfault_min == NULL)
2411 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002412 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002413 perf_evlist__add(evlist, pgfault_min);
2414 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002415
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002416 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002417 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2418 trace__sched_stat_runtime))
2419 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002420
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002421 /*
2422 * If a global cgroup was set, apply it to all the events without an
2423 * explicit cgroup. I.e.:
2424 *
2425 * trace -G A -e sched:*switch
2426 *
2427 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2428 * _and_ sched:sched_switch to the 'A' cgroup, while:
2429 *
2430 * trace -e sched:*switch -G A
2431 *
2432 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2433 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2434 * a cgroup (on the root cgroup, sys wide, etc).
2435 *
2436 * Multiple cgroups:
2437 *
2438 * trace -G A -e sched:*switch -G B
2439 *
2440 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2441 * to the 'B' cgroup.
2442 *
2443 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2444 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2445 */
2446 if (trace->cgroup)
2447 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2448
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002449 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2450 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002451 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002452 goto out_delete_evlist;
2453 }
2454
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002455 err = trace__symbols_init(trace, evlist);
2456 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002457 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002458 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002459 }
2460
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002461 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002462
Namhyung Kimf15eb532012-10-05 14:02:16 +09002463 signal(SIGCHLD, sig_handler);
2464 signal(SIGINT, sig_handler);
2465
2466 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002467 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002468 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002469 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002470 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002471 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002472 }
2473 }
2474
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002475 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002476 if (err < 0)
2477 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002478
Wang Nanba504232016-02-26 09:31:54 +00002479 err = bpf__apply_obj_config();
2480 if (err) {
2481 char errbuf[BUFSIZ];
2482
2483 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2484 pr_err("ERROR: Apply config to BPF failed: %s\n",
2485 errbuf);
2486 goto out_error_open;
2487 }
2488
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002489 /*
2490 * Better not use !target__has_task() here because we need to cover the
2491 * case where no threads were specified in the command line, but a
2492 * workload was, and in that case we will fill in the thread_map when
2493 * we fork the workload in perf_evlist__prepare_workload.
2494 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002495 if (trace->filter_pids.nr > 0)
2496 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002497 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002498 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002499
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002500 if (err < 0)
2501 goto out_error_mem;
2502
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002503 if (trace->ev_qualifier_ids.nr > 0) {
2504 err = trace__set_ev_qualifier_filter(trace);
2505 if (err < 0)
2506 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002507
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002508 pr_debug("event qualifier tracepoint filter: %s\n",
2509 trace->syscalls.events.sys_exit->filter);
2510 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002511
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002512 err = perf_evlist__apply_filters(evlist, &evsel);
2513 if (err < 0)
2514 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002515
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002516 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002517 if (err < 0)
2518 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002519
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002520 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002521 perf_evlist__enable(evlist);
2522
Namhyung Kimf15eb532012-10-05 14:02:16 +09002523 if (forks)
2524 perf_evlist__start_workload(evlist);
2525
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002526 if (trace->opts.initial_delay) {
2527 usleep(trace->opts.initial_delay * 1000);
2528 perf_evlist__enable(evlist);
2529 }
2530
Jiri Olsae13798c2015-06-23 00:36:02 +02002531 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002532 evlist->threads->nr > 1 ||
2533 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002534
2535 /*
2536 * Now that we already used evsel->attr to ask the kernel to setup the
2537 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2538 * trace__resolve_callchain(), allowing per-event max-stack settings
2539 * to override an explicitely set --max-stack global setting.
2540 */
2541 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002542 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002543 evsel->attr.sample_max_stack == 0)
2544 evsel->attr.sample_max_stack = trace->max_stack;
2545 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002546again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002547 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002548
2549 for (i = 0; i < evlist->nr_mmaps; i++) {
2550 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002551 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002552
Kan Liangd7f55c62018-03-01 18:08:59 -05002553 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002554 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002555 continue;
2556
Kan Liang0019dc872018-03-06 10:36:06 -05002557 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002558 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002559
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002560 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002561
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002562 err = perf_evlist__parse_sample(evlist, event, &sample);
2563 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002564 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002565 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002566 }
2567
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002568 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002569next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002570 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002571
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002572 if (interrupted)
2573 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002574
2575 if (done && !draining) {
2576 perf_evlist__disable(evlist);
2577 draining = true;
2578 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002579 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002580 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002581 }
2582
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002583 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002584 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002585
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002586 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2587 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2588 draining = true;
2589
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002590 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002591 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002592 } else {
2593 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002594 }
2595
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002596out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002597 thread__zput(trace->current);
2598
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002599 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002600
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002601 if (!err) {
2602 if (trace->summary)
2603 trace__fprintf_thread_summary(trace, trace->output);
2604
2605 if (trace->show_tool_stats) {
2606 fprintf(trace->output, "Stats:\n "
2607 " vfs_getname : %" PRIu64 "\n"
2608 " proc_getname: %" PRIu64 "\n",
2609 trace->stats.vfs_getname,
2610 trace->stats.proc_getname);
2611 }
2612 }
David Ahernbf2575c2013-10-08 21:26:53 -06002613
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002614out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002615 trace__symbols__exit(trace);
2616
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002617 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002618 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002619 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002620 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002621 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002622{
2623 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002624
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002625out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002626 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002627 goto out_error;
2628
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002629out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002630 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002631 goto out_error;
2632
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002633out_error_mmap:
2634 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2635 goto out_error;
2636
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002637out_error_open:
2638 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2639
2640out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002641 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302642 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002643
2644out_error_apply_filters:
2645 fprintf(trace->output,
2646 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2647 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002648 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002649 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002650}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002651out_error_mem:
2652 fprintf(trace->output, "Not enough memory to run!\n");
2653 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002654
2655out_errno:
2656 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2657 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002658}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002659
David Ahern6810fc92013-08-28 22:29:52 -06002660static int trace__replay(struct trace *trace)
2661{
2662 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002663 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002664 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002665 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002666 .file = {
2667 .path = input_name,
2668 },
2669 .mode = PERF_DATA_MODE_READ,
2670 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002671 };
David Ahern6810fc92013-08-28 22:29:52 -06002672 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002673 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002674 int err = -1;
2675
2676 trace->tool.sample = trace__process_sample;
2677 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002678 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002679 trace->tool.comm = perf_event__process_comm;
2680 trace->tool.exit = perf_event__process_exit;
2681 trace->tool.fork = perf_event__process_fork;
2682 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302683 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002684 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302685 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002686
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002687 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002688 trace->tool.ordering_requires_timestamps = true;
2689
2690 /* add tid to output */
2691 trace->multiple_threads = true;
2692
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002693 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002694 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002695 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002696
David Ahernaa07df62016-11-25 09:29:52 -07002697 if (trace->opts.target.pid)
2698 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2699
2700 if (trace->opts.target.tid)
2701 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2702
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002703 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002704 goto out;
2705
David Ahern8fb598e2013-09-28 13:13:00 -06002706 trace->host = &session->machines.host;
2707
David Ahern6810fc92013-08-28 22:29:52 -06002708 err = perf_session__set_tracepoints_handlers(session, handlers);
2709 if (err)
2710 goto out;
2711
Namhyung Kim003824e2013-11-12 15:25:00 +09002712 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2713 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002714 /* older kernels have syscalls tp versus raw_syscalls */
2715 if (evsel == NULL)
2716 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2717 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002718
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002719 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002720 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002721 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002722 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2723 goto out;
2724 }
2725
2726 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2727 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002728 if (evsel == NULL)
2729 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2730 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002731 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002732 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002733 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002734 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002735 goto out;
2736 }
2737
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002738 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002739 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2740 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2741 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2742 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2743 evsel->handler = trace__pgfault;
2744 }
2745
David Ahern6810fc92013-08-28 22:29:52 -06002746 setup_pager();
2747
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002748 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002749 if (err)
2750 pr_err("Failed to process events, error %d", err);
2751
David Ahernbf2575c2013-10-08 21:26:53 -06002752 else if (trace->summary)
2753 trace__fprintf_thread_summary(trace, trace->output);
2754
David Ahern6810fc92013-08-28 22:29:52 -06002755out:
2756 perf_session__delete(session);
2757
2758 return err;
2759}
2760
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002761static size_t trace__fprintf_threads_header(FILE *fp)
2762{
2763 size_t printed;
2764
Pekka Enberg99ff7152013-11-12 16:42:14 +02002765 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002766
2767 return printed;
2768}
2769
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002770DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2771 struct stats *stats;
2772 double msecs;
2773 int syscall;
2774)
2775{
2776 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2777 struct stats *stats = source->priv;
2778
2779 entry->syscall = source->i;
2780 entry->stats = stats;
2781 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2782}
2783
David Ahernbf2575c2013-10-08 21:26:53 -06002784static size_t thread__dump_stats(struct thread_trace *ttrace,
2785 struct trace *trace, FILE *fp)
2786{
David Ahernbf2575c2013-10-08 21:26:53 -06002787 size_t printed = 0;
2788 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002789 struct rb_node *nd;
2790 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002791
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002792 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002793 return 0;
2794
2795 printed += fprintf(fp, "\n");
2796
Milian Wolff834fd462015-08-06 11:24:29 +02002797 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2798 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2799 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002800
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002801 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002802 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002803 if (stats) {
2804 double min = (double)(stats->min) / NSEC_PER_MSEC;
2805 double max = (double)(stats->max) / NSEC_PER_MSEC;
2806 double avg = avg_stats(stats);
2807 double pct;
2808 u64 n = (u64) stats->n;
2809
2810 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2811 avg /= NSEC_PER_MSEC;
2812
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002813 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002814 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002815 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002816 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002817 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002818 }
David Ahernbf2575c2013-10-08 21:26:53 -06002819 }
2820
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002821 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002822 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002823
2824 return printed;
2825}
2826
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002827static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002828{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002829 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002830 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002831 double ratio;
2832
2833 if (ttrace == NULL)
2834 return 0;
2835
2836 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2837
Pekka Enberg15e65c62013-11-14 18:43:30 +02002838 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002839 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002840 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002841 if (ttrace->pfmaj)
2842 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2843 if (ttrace->pfmin)
2844 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002845 if (trace->sched)
2846 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2847 else if (fputc('\n', fp) != EOF)
2848 ++printed;
2849
David Ahernbf2575c2013-10-08 21:26:53 -06002850 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002851
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002852 return printed;
2853}
David Ahern896cbb52013-09-28 13:12:59 -06002854
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002855static unsigned long thread__nr_events(struct thread_trace *ttrace)
2856{
2857 return ttrace ? ttrace->nr_events : 0;
2858}
2859
2860DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2861 struct thread *thread;
2862)
2863{
2864 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002865}
2866
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002867static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2868{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002869 size_t printed = trace__fprintf_threads_header(fp);
2870 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002871 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002872
Kan Liang91e467b2017-09-10 19:23:14 -07002873 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2874 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2875
2876 if (threads == NULL) {
2877 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2878 return 0;
2879 }
2880
2881 resort_rb__for_each_entry(nd, threads)
2882 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2883
2884 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002885 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002886 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002887}
2888
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002889static int trace__set_duration(const struct option *opt, const char *str,
2890 int unset __maybe_unused)
2891{
2892 struct trace *trace = opt->value;
2893
2894 trace->duration_filter = atof(str);
2895 return 0;
2896}
2897
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002898static int trace__set_filter_pids(const struct option *opt, const char *str,
2899 int unset __maybe_unused)
2900{
2901 int ret = -1;
2902 size_t i;
2903 struct trace *trace = opt->value;
2904 /*
2905 * FIXME: introduce a intarray class, plain parse csv and create a
2906 * { int nr, int entries[] } struct...
2907 */
2908 struct intlist *list = intlist__new(str);
2909
2910 if (list == NULL)
2911 return -1;
2912
2913 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2914 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2915
2916 if (trace->filter_pids.entries == NULL)
2917 goto out;
2918
2919 trace->filter_pids.entries[0] = getpid();
2920
2921 for (i = 1; i < trace->filter_pids.nr; ++i)
2922 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2923
2924 intlist__delete(list);
2925 ret = 0;
2926out:
2927 return ret;
2928}
2929
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002930static int trace__open_output(struct trace *trace, const char *filename)
2931{
2932 struct stat st;
2933
2934 if (!stat(filename, &st) && st.st_size) {
2935 char oldname[PATH_MAX];
2936
2937 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2938 unlink(oldname);
2939 rename(filename, oldname);
2940 }
2941
2942 trace->output = fopen(filename, "w");
2943
2944 return trace->output == NULL ? -errno : 0;
2945}
2946
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002947static int parse_pagefaults(const struct option *opt, const char *str,
2948 int unset __maybe_unused)
2949{
2950 int *trace_pgfaults = opt->value;
2951
2952 if (strcmp(str, "all") == 0)
2953 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2954 else if (strcmp(str, "maj") == 0)
2955 *trace_pgfaults |= TRACE_PFMAJ;
2956 else if (strcmp(str, "min") == 0)
2957 *trace_pgfaults |= TRACE_PFMIN;
2958 else
2959 return -1;
2960
2961 return 0;
2962}
2963
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002964static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2965{
2966 struct perf_evsel *evsel;
2967
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002968 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002969 evsel->handler = handler;
2970}
2971
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002972/*
2973 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2974 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2975 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2976 *
2977 * It'd be better to introduce a parse_options() variant that would return a
2978 * list with the terms it didn't match to an event...
2979 */
2980static int trace__parse_events_option(const struct option *opt, const char *str,
2981 int unset __maybe_unused)
2982{
2983 struct trace *trace = (struct trace *)opt->value;
2984 const char *s = str;
2985 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002986 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002987 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2988 char group_name[PATH_MAX];
2989
2990 if (strace_groups_dir == NULL)
2991 return -1;
2992
2993 if (*s == '!') {
2994 ++s;
2995 trace->not_ev_qualifier = true;
2996 }
2997
2998 while (1) {
2999 if ((sep = strchr(s, ',')) != NULL)
3000 *sep = '\0';
3001
3002 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003003 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3004 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003005 list = 1;
3006 } else {
3007 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3008 if (access(group_name, R_OK) == 0)
3009 list = 1;
3010 }
3011
3012 if (lists[list]) {
3013 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3014 } else {
3015 lists[list] = malloc(len);
3016 if (lists[list] == NULL)
3017 goto out;
3018 strcpy(lists[list], s);
3019 }
3020
3021 if (!sep)
3022 break;
3023
3024 *sep = ',';
3025 s = sep + 1;
3026 }
3027
3028 if (lists[1] != NULL) {
3029 struct strlist_config slist_config = {
3030 .dirname = strace_groups_dir,
3031 };
3032
3033 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3034 if (trace->ev_qualifier == NULL) {
3035 fputs("Not enough memory to parse event qualifier", trace->output);
3036 goto out;
3037 }
3038
3039 if (trace__validate_ev_qualifier(trace))
3040 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003041 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003042 }
3043
3044 err = 0;
3045
3046 if (lists[0]) {
3047 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3048 "event selector. use 'perf list' to list available events",
3049 parse_events_option);
3050 err = parse_events_option(&o, lists[0], 0);
3051 }
3052out:
3053 if (sep)
3054 *sep = ',';
3055
3056 return err;
3057}
3058
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003059static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3060{
3061 struct trace *trace = opt->value;
3062
3063 if (!list_empty(&trace->evlist->entries))
3064 return parse_cgroups(opt, str, unset);
3065
3066 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3067
3068 return 0;
3069}
3070
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003071int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003072{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003073 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003074 "perf trace [<options>] [<command>]",
3075 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003076 "perf trace record [<options>] [<command>]",
3077 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003078 NULL
3079 };
3080 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003081 .syscalls = {
3082 . max = -1,
3083 },
3084 .opts = {
3085 .target = {
3086 .uid = UINT_MAX,
3087 .uses_mmap = true,
3088 },
3089 .user_freq = UINT_MAX,
3090 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003091 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003092 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003093 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003094 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003095 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003096 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003097 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003098 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003099 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003100 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003101 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003102 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003103 OPT_CALLBACK('e', "event", &trace, "event",
3104 "event/syscall selector. use 'perf list' to list available events",
3105 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003106 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3107 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003108 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003109 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3110 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003111 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003112 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003113 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3114 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003115 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003116 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003117 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3118 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003119 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003120 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003121 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003122 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003123 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003124 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003125 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3126 "number of mmap data pages",
3127 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003128 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003129 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003130 OPT_CALLBACK(0, "duration", &trace, "float",
3131 "show only events with duration > N.M ms",
3132 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003133 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003134 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003135 OPT_BOOLEAN('T', "time", &trace.full_time,
3136 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003137 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3138 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003139 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3140 "Show only syscall summary with statistics"),
3141 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3142 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003143 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3144 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003145 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003146 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003147 OPT_CALLBACK(0, "call-graph", &trace.opts,
3148 "record_mode[,record_size]", record_callchain_help,
3149 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003150 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3151 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003152 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3153 "Set the minimum stack depth when parsing the callchain, "
3154 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003155 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3156 "Set the maximum stack depth when parsing the callchain, "
3157 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003158 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003159 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3160 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003161 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3162 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003163 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3164 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003165 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3166 "ms to wait before starting measurement after program "
3167 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003168 OPT_END()
3169 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003170 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003171 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003172 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003173 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003174 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003175
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003176 signal(SIGSEGV, sighandler_dump_stack);
3177 signal(SIGFPE, sighandler_dump_stack);
3178
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003179 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003180 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003181
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003182 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003183 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003184 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003185 goto out;
3186 }
3187
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003188 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3189 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003190
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003191 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3192 usage_with_options_msg(trace_usage, trace_options,
3193 "cgroup monitoring only available in system-wide mode");
3194 }
3195
Wang Nand7888572016-04-08 15:07:24 +00003196 err = bpf__setup_stdout(trace.evlist);
3197 if (err) {
3198 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3199 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3200 goto out;
3201 }
3202
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003203 err = -1;
3204
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003205 if (trace.trace_pgfaults) {
3206 trace.opts.sample_address = true;
3207 trace.opts.sample_time = true;
3208 }
3209
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003210 if (trace.opts.mmap_pages == UINT_MAX)
3211 mmap_pages_user_set = false;
3212
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003213 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003214 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003215 max_stack_user_set = false;
3216 }
3217
3218#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003219 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003220 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003221 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003222#endif
3223
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003224 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003225 if (!mmap_pages_user_set && geteuid() == 0)
3226 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3227
Milian Wolff566a0882016-04-08 13:34:15 +02003228 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003229 }
Milian Wolff566a0882016-04-08 13:34:15 +02003230
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003231 if (trace.evlist->nr_entries > 0)
3232 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3233
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003234 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3235 return trace__record(&trace, argc-1, &argv[1]);
3236
3237 /* summary_only implies summary option, but don't overwrite summary if set */
3238 if (trace.summary_only)
3239 trace.summary = trace.summary_only;
3240
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003241 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3242 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003243 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003244 }
3245
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003246 if (output_name != NULL) {
3247 err = trace__open_output(&trace, output_name);
3248 if (err < 0) {
3249 perror("failed to create output file");
3250 goto out;
3251 }
3252 }
3253
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003254 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003255 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003256 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003257 fprintf(trace.output, "%s", bf);
3258 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003259 }
3260
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003261 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003262 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003263 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003264 fprintf(trace.output, "%s", bf);
3265 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003266 }
3267
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003268 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003269 trace.opts.target.system_wide = true;
3270
David Ahern6810fc92013-08-28 22:29:52 -06003271 if (input_name)
3272 err = trace__replay(&trace);
3273 else
3274 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003275
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003276out_close:
3277 if (output_name != NULL)
3278 fclose(trace.output);
3279out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003280 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003281}