blob: e7f1b182fc153f227f8541e485c47a27115a111e [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030022#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030023#include "util/debug.h"
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +010024#include "util/env.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030025#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030026#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060027#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030028#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030029#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060030#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030031#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060032#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030033#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060034#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030035#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060036#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030037#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010038#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070039#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000040#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020041#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030042#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030043#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030044#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030045#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030046
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030047#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030048#include <inttypes.h>
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030049#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030050#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030051#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030052#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020053#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030054#include <linux/filter.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030055#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030056#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030057#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030058#include <linux/time64.h>
Arnaldo Carvalho de Melobafae982018-01-22 16:42:16 -030059#include <fcntl.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030060
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030061#include "sane_ctype.h"
62
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030063#ifndef O_CLOEXEC
64# define O_CLOEXEC 02000000
65#endif
66
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030067#ifndef F_LINUX_SPECIFIC_BASE
68# define F_LINUX_SPECIFIC_BASE 1024
69#endif
70
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030071struct trace {
72 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030073 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030074 struct {
75 int max;
76 struct syscall *table;
77 struct {
78 struct perf_evsel *sys_enter,
79 *sys_exit;
80 } events;
81 } syscalls;
82 struct record_opts opts;
83 struct perf_evlist *evlist;
84 struct machine *host;
85 struct thread *current;
86 u64 base_time;
87 FILE *output;
88 unsigned long nr_events;
89 struct strlist *ev_qualifier;
90 struct {
91 size_t nr;
92 int *entries;
93 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030094 struct {
95 size_t nr;
96 pid_t *entries;
97 } filter_pids;
98 double duration_filter;
99 double runtime_ms;
100 struct {
101 u64 vfs_getname,
102 proc_getname;
103 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300104 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300105 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300106 bool not_ev_qualifier;
107 bool live;
108 bool full_time;
109 bool sched;
110 bool multiple_threads;
111 bool summary;
112 bool summary_only;
113 bool show_comm;
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -0300114 bool print_sample;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300115 bool show_tool_stats;
116 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300117 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300118 bool force;
119 bool vfs_getname;
120 int trace_pgfaults;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -0300121 int open_id;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300122};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300123
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300124struct tp_field {
125 int offset;
126 union {
127 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
128 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
129 };
130};
131
132#define TP_UINT_FIELD(bits) \
133static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
134{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500135 u##bits value; \
136 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
137 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300138}
139
140TP_UINT_FIELD(8);
141TP_UINT_FIELD(16);
142TP_UINT_FIELD(32);
143TP_UINT_FIELD(64);
144
145#define TP_UINT_FIELD__SWAPPED(bits) \
146static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
147{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500148 u##bits value; \
149 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300150 return bswap_##bits(value);\
151}
152
153TP_UINT_FIELD__SWAPPED(16);
154TP_UINT_FIELD__SWAPPED(32);
155TP_UINT_FIELD__SWAPPED(64);
156
157static int tp_field__init_uint(struct tp_field *field,
158 struct format_field *format_field,
159 bool needs_swap)
160{
161 field->offset = format_field->offset;
162
163 switch (format_field->size) {
164 case 1:
165 field->integer = tp_field__u8;
166 break;
167 case 2:
168 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
169 break;
170 case 4:
171 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
172 break;
173 case 8:
174 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
175 break;
176 default:
177 return -1;
178 }
179
180 return 0;
181}
182
183static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
184{
185 return sample->raw_data + field->offset;
186}
187
188static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
189{
190 field->offset = format_field->offset;
191 field->pointer = tp_field__ptr;
192 return 0;
193}
194
195struct syscall_tp {
196 struct tp_field id;
197 union {
198 struct tp_field args, ret;
199 };
200};
201
202static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
203 struct tp_field *field,
204 const char *name)
205{
206 struct format_field *format_field = perf_evsel__field(evsel, name);
207
208 if (format_field == NULL)
209 return -1;
210
211 return tp_field__init_uint(field, format_field, evsel->needs_swap);
212}
213
214#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
215 ({ struct syscall_tp *sc = evsel->priv;\
216 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
217
218static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
219 struct tp_field *field,
220 const char *name)
221{
222 struct format_field *format_field = perf_evsel__field(evsel, name);
223
224 if (format_field == NULL)
225 return -1;
226
227 return tp_field__init_ptr(field, format_field);
228}
229
230#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
231 ({ struct syscall_tp *sc = evsel->priv;\
232 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
233
234static void perf_evsel__delete_priv(struct perf_evsel *evsel)
235{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300236 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300237 perf_evsel__delete(evsel);
238}
239
Namhyung Kim96695d42013-11-12 08:51:45 -0300240static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
241{
242 evsel->priv = malloc(sizeof(struct syscall_tp));
243 if (evsel->priv != NULL) {
244 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
245 goto out_delete;
246
247 evsel->handler = handler;
248 return 0;
249 }
250
251 return -ENOMEM;
252
253out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300254 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300255 return -ENOENT;
256}
257
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300258static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300259{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300260 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300261
David Ahern9aca7f12013-12-04 19:41:39 -0700262 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200263 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700264 evsel = perf_evsel__newtp("syscalls", direction);
265
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200266 if (IS_ERR(evsel))
267 return NULL;
268
269 if (perf_evsel__init_syscall_tp(evsel, handler))
270 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300271
272 return evsel;
273
274out_delete:
275 perf_evsel__delete_priv(evsel);
276 return NULL;
277}
278
279#define perf_evsel__sc_tp_uint(evsel, name, sample) \
280 ({ struct syscall_tp *fields = evsel->priv; \
281 fields->name.integer(&fields->name, sample); })
282
283#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
284 ({ struct syscall_tp *fields = evsel->priv; \
285 fields->name.pointer(&fields->name, sample); })
286
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300287size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
288{
289 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300290
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300291 if (idx < 0 || idx >= sa->nr_entries)
292 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300293
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300294 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300295}
296
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300297static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
298 const char *intfmt,
299 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300300{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300301 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300302}
303
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300304static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
305 struct syscall_arg *arg)
306{
307 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
308}
309
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300310#define SCA_STRARRAY syscall_arg__scnprintf_strarray
311
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300312struct strarrays {
313 int nr_entries;
314 struct strarray **entries;
315};
316
317#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
318 .nr_entries = ARRAY_SIZE(array), \
319 .entries = array, \
320}
321
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300322size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
323 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300324{
325 struct strarrays *sas = arg->parm;
326 int i;
327
328 for (i = 0; i < sas->nr_entries; ++i) {
329 struct strarray *sa = sas->entries[i];
330 int idx = arg->val - sa->offset;
331
332 if (idx >= 0 && idx < sa->nr_entries) {
333 if (sa->entries[idx] == NULL)
334 break;
335 return scnprintf(bf, size, "%s", sa->entries[idx]);
336 }
337 }
338
339 return scnprintf(bf, size, "%d", arg->val);
340}
341
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300342#ifndef AT_FDCWD
343#define AT_FDCWD -100
344#endif
345
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300346static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
347 struct syscall_arg *arg)
348{
349 int fd = arg->val;
350
351 if (fd == AT_FDCWD)
352 return scnprintf(bf, size, "CWD");
353
354 return syscall_arg__scnprintf_fd(bf, size, arg);
355}
356
357#define SCA_FDAT syscall_arg__scnprintf_fd_at
358
359static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
360 struct syscall_arg *arg);
361
362#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
363
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300364size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300365{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300366 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300367}
368
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300369size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300370{
371 return scnprintf(bf, size, "%d", arg->val);
372}
373
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300374size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
375{
376 return scnprintf(bf, size, "%ld", arg->val);
377}
378
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300379static const char *bpf_cmd[] = {
380 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
381 "MAP_GET_NEXT_KEY", "PROG_LOAD",
382};
383static DEFINE_STRARRAY(bpf_cmd);
384
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300385static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
386static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300387
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300388static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
389static DEFINE_STRARRAY(itimers);
390
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300391static const char *keyctl_options[] = {
392 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
393 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
394 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
395 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
396 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
397};
398static DEFINE_STRARRAY(keyctl_options);
399
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300400static const char *whences[] = { "SET", "CUR", "END",
401#ifdef SEEK_DATA
402"DATA",
403#endif
404#ifdef SEEK_HOLE
405"HOLE",
406#endif
407};
408static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300409
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300410static const char *fcntl_cmds[] = {
411 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300412 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
413 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
414 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300415};
416static DEFINE_STRARRAY(fcntl_cmds);
417
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300418static const char *fcntl_linux_specific_cmds[] = {
419 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
420 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300421 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300422};
423
424static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
425
426static struct strarray *fcntl_cmds_arrays[] = {
427 &strarray__fcntl_cmds,
428 &strarray__fcntl_linux_specific_cmds,
429};
430
431static DEFINE_STRARRAYS(fcntl_cmds_arrays);
432
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300433static const char *rlimit_resources[] = {
434 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
435 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
436 "RTTIME",
437};
438static DEFINE_STRARRAY(rlimit_resources);
439
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300440static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
441static DEFINE_STRARRAY(sighow);
442
David Ahern4f8c1b72013-09-22 19:45:00 -0600443static const char *clockid[] = {
444 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300445 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
446 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600447};
448static DEFINE_STRARRAY(clockid);
449
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300450static const char *socket_families[] = {
451 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
452 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
453 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
454 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
455 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
456 "ALG", "NFC", "VSOCK",
457};
458static DEFINE_STRARRAY(socket_families);
459
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300460static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
461 struct syscall_arg *arg)
462{
463 size_t printed = 0;
464 int mode = arg->val;
465
466 if (mode == F_OK) /* 0 */
467 return scnprintf(bf, size, "F");
468#define P_MODE(n) \
469 if (mode & n##_OK) { \
470 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
471 mode &= ~n##_OK; \
472 }
473
474 P_MODE(R);
475 P_MODE(W);
476 P_MODE(X);
477#undef P_MODE
478
479 if (mode)
480 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
481
482 return printed;
483}
484
485#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
486
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300487static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
488 struct syscall_arg *arg);
489
490#define SCA_FILENAME syscall_arg__scnprintf_filename
491
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300492static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
493 struct syscall_arg *arg)
494{
495 int printed = 0, flags = arg->val;
496
497#define P_FLAG(n) \
498 if (flags & O_##n) { \
499 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
500 flags &= ~O_##n; \
501 }
502
503 P_FLAG(CLOEXEC);
504 P_FLAG(NONBLOCK);
505#undef P_FLAG
506
507 if (flags)
508 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
509
510 return printed;
511}
512
513#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
514
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300515#ifndef GRND_NONBLOCK
516#define GRND_NONBLOCK 0x0001
517#endif
518#ifndef GRND_RANDOM
519#define GRND_RANDOM 0x0002
520#endif
521
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300522static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
523 struct syscall_arg *arg)
524{
525 int printed = 0, flags = arg->val;
526
527#define P_FLAG(n) \
528 if (flags & GRND_##n) { \
529 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
530 flags &= ~GRND_##n; \
531 }
532
533 P_FLAG(RANDOM);
534 P_FLAG(NONBLOCK);
535#undef P_FLAG
536
537 if (flags)
538 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
539
540 return printed;
541}
542
543#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
544
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300545#define STRARRAY(name, array) \
546 { .scnprintf = SCA_STRARRAY, \
547 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300548
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +0100549#include "trace/beauty/arch_errno_names.c"
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300550#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300551#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300552#include "trace/beauty/futex_val3.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300553#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300554#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300555#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300556#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300557#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300558#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300559#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300560#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300561#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300562#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300563#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300564
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300565struct syscall_arg_fmt {
566 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
567 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300568 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300569 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300570};
571
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300572static struct syscall_fmt {
573 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300574 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300575 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300576 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300577 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300578 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300579 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300580} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300581 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300582 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300583 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300584 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300585 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300586 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300587 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300588 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300589 { .name = "clone", .errpid = true, .nr_args = 5,
590 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
591 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
592 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
593 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
594 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300595 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300596 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300597 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300598 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300599 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300600 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300601 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300602 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300603 { .name = "fchownat",
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 = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300606 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300607 .parm = &strarrays__fcntl_cmds_arrays,
608 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300609 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300610 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300611 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300612 { .name = "fstat", .alias = "newfstat", },
613 { .name = "fstatat", .alias = "newfstatat", },
614 { .name = "futex",
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300615 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
616 [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300617 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300618 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300619 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300620 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300621 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300622 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300623 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300624 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300625 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300626 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300627 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo2d1073d2018-01-09 12:03:47 -0300628 { .name = "gettid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300629 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300630 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300631#if defined(__i386__) || defined(__x86_64__)
632/*
633 * FIXME: Make this available to all arches.
634 */
Arnaldo Carvalho de Melo1cc47f2d2017-07-31 13:20:14 -0300635 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300636 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300637#else
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#endif
Arnaldo Carvalho de Melo1de30382017-10-31 11:32:23 -0300640 { .name = "kcmp", .nr_args = 5,
641 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
642 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
643 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
644 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
645 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300646 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300647 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300648 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300649 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300650 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300651 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300652 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300654 { .name = "lstat", .alias = "newlstat", },
655 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300656 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
657 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300658 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300659 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300660 { .name = "mknodat",
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 = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300663 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300664 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300665 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300666 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200667/* The standard mmap maps to old_mmap on s390x */
668#if defined(__s390x__)
669 .alias = "old_mmap",
670#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300671 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
672 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
673 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
676 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300677 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300678 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300679 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300680 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
681 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
682 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300683 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300684 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300685 { .name = "munmap",
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 = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300688 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300689 { .name = "newfstatat",
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 = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300692 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300693 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300694 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
695 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300696 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300697 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
698 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300699 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300700 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
701 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
702 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300705 { .name = "pkey_alloc",
706 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
707 { .name = "pkey_free",
708 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
709 { .name = "pkey_mprotect",
710 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
711 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
712 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "poll", .timeout = true, },
714 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300715 { .name = "prctl", .alias = "arch_prctl",
716 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
717 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
718 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300719 { .name = "pread", .alias = "pread64", },
720 { .name = "preadv", .alias = "pread", },
721 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300722 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300723 { .name = "pwrite", .alias = "pwrite64", },
724 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300725 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300726 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300727 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300728 { .name = "recvmmsg",
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 = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300731 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300732 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300733 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300734 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300735 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300736 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300737 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300738 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300745 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
746 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300747 { .name = "select", .timeout = true, },
748 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300749 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300750 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300754 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300755 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300756 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300757 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300758 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300759 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300760 .arg = { [0] = STRARRAY(family, socket_families),
761 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [0] = STRARRAY(family, socket_families),
764 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300765 { .name = "stat", .alias = "newstat", },
766 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
768 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
769 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300770 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300771 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300772 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300773 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300774 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300775 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300776 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300777 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300778 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300779 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300780 { .name = "uname", .alias = "newuname", },
781 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300782 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300783 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300784 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300785 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300786 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300787 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300788 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300789};
790
791static int syscall_fmt__cmp(const void *name, const void *fmtp)
792{
793 const struct syscall_fmt *fmt = fmtp;
794 return strcmp(name, fmt->name);
795}
796
797static struct syscall_fmt *syscall_fmt__find(const char *name)
798{
799 const int nmemb = ARRAY_SIZE(syscall_fmts);
800 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
801}
802
803struct syscall {
804 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300805 int nr_args;
806 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300807 const char *name;
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -0300808 bool is_exit;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300809 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300810 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300811};
812
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300813/*
814 * We need to have this 'calculated' boolean because in some cases we really
815 * don't know what is the duration of a syscall, for instance, when we start
816 * a session and some threads are waiting for a syscall to finish, say 'poll',
817 * in which case all we can do is to print "( ? ) for duration and for the
818 * start timestamp.
819 */
820static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200821{
822 double duration = (double)t / NSEC_PER_MSEC;
823 size_t printed = fprintf(fp, "(");
824
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300825 if (!calculated)
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -0300826 printed += fprintf(fp, " ");
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300827 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200828 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
829 else if (duration >= 0.01)
830 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
831 else
832 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300833 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200834}
835
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300836/**
837 * filename.ptr: The filename char pointer that will be vfs_getname'd
838 * filename.entry_str_pos: Where to insert the string translated from
839 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300840 * ret_scnprintf: syscall args may set this to a different syscall return
841 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300842 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300843struct thread_trace {
844 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300845 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300846 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400847 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300848 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300849 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300850 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300851 struct {
852 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300853 short int entry_str_pos;
854 bool pending_open;
855 unsigned int namelen;
856 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300857 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300858 struct {
859 int max;
860 char **table;
861 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600862
863 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300864};
865
866static struct thread_trace *thread_trace__new(void)
867{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300868 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
869
870 if (ttrace)
871 ttrace->paths.max = -1;
872
David Ahernbf2575c2013-10-08 21:26:53 -0600873 ttrace->syscall_stats = intlist__new(NULL);
874
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300875 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876}
877
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300878static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300879{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300880 struct thread_trace *ttrace;
881
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300882 if (thread == NULL)
883 goto fail;
884
Namhyung Kim89dceb22014-10-06 09:46:03 +0900885 if (thread__priv(thread) == NULL)
886 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300887
Namhyung Kim89dceb22014-10-06 09:46:03 +0900888 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300889 goto fail;
890
Namhyung Kim89dceb22014-10-06 09:46:03 +0900891 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300892 ++ttrace->nr_events;
893
894 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300896 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897 "WARNING: not enough memory, dropping samples!\n");
898 return NULL;
899}
900
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300901
902void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300903 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300904{
905 struct thread_trace *ttrace = thread__priv(arg->thread);
906
907 ttrace->ret_scnprintf = ret_scnprintf;
908}
909
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400910#define TRACE_PFMAJ (1 << 0)
911#define TRACE_PFMIN (1 << 1)
912
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300913static const size_t trace__entry_str_size = 2048;
914
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300915static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300916{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900917 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918
919 if (fd > ttrace->paths.max) {
920 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
921
922 if (npath == NULL)
923 return -1;
924
925 if (ttrace->paths.max != -1) {
926 memset(npath + ttrace->paths.max + 1, 0,
927 (fd - ttrace->paths.max) * sizeof(char *));
928 } else {
929 memset(npath, 0, (fd + 1) * sizeof(char *));
930 }
931
932 ttrace->paths.table = npath;
933 ttrace->paths.max = fd;
934 }
935
936 ttrace->paths.table[fd] = strdup(pathname);
937
938 return ttrace->paths.table[fd] != NULL ? 0 : -1;
939}
940
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300941static int thread__read_fd_path(struct thread *thread, int fd)
942{
943 char linkname[PATH_MAX], pathname[PATH_MAX];
944 struct stat st;
945 int ret;
946
947 if (thread->pid_ == thread->tid) {
948 scnprintf(linkname, sizeof(linkname),
949 "/proc/%d/fd/%d", thread->pid_, fd);
950 } else {
951 scnprintf(linkname, sizeof(linkname),
952 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
953 }
954
955 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
956 return -1;
957
958 ret = readlink(linkname, pathname, sizeof(pathname));
959
960 if (ret < 0 || ret > st.st_size)
961 return -1;
962
963 pathname[ret] = '\0';
964 return trace__set_fd_pathname(thread, fd, pathname);
965}
966
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300967static const char *thread__fd_path(struct thread *thread, int fd,
968 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300969{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900970 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300971
972 if (ttrace == NULL)
973 return NULL;
974
975 if (fd < 0)
976 return NULL;
977
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300978 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300979 if (!trace->live)
980 return NULL;
981 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -0300982 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300983 return NULL;
984 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300985
986 return ttrace->paths.table[fd];
987}
988
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -0300989size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300990{
991 int fd = arg->val;
992 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -0300993 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300994
995 if (path)
996 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
997
998 return printed;
999}
1000
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -03001001size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1002{
1003 size_t printed = scnprintf(bf, size, "%d", fd);
1004 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1005
1006 if (thread) {
1007 const char *path = thread__fd_path(thread, fd, trace);
1008
1009 if (path)
1010 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1011
1012 thread__put(thread);
1013 }
1014
1015 return printed;
1016}
1017
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001018static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1019 struct syscall_arg *arg)
1020{
1021 int fd = arg->val;
1022 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001023 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001024
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001025 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1026 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027
1028 return printed;
1029}
1030
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001031static void thread__set_filename_pos(struct thread *thread, const char *bf,
1032 unsigned long ptr)
1033{
1034 struct thread_trace *ttrace = thread__priv(thread);
1035
1036 ttrace->filename.ptr = ptr;
1037 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1038}
1039
1040static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1041 struct syscall_arg *arg)
1042{
1043 unsigned long ptr = arg->val;
1044
1045 if (!arg->trace->vfs_getname)
1046 return scnprintf(bf, size, "%#x", ptr);
1047
1048 thread__set_filename_pos(arg->thread, bf, ptr);
1049 return 0;
1050}
1051
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001052static bool trace__filter_duration(struct trace *trace, double t)
1053{
1054 return t < (trace->duration_filter * NSEC_PER_MSEC);
1055}
1056
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001057static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001058{
1059 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1060
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001061 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001062}
1063
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001064/*
1065 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1066 * using ttrace->entry_time for a thread that receives a sys_exit without
1067 * first having received a sys_enter ("poll" issued before tracing session
1068 * starts, lost sys_enter exit due to ring buffer overflow).
1069 */
1070static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1071{
1072 if (tstamp > 0)
1073 return __trace__fprintf_tstamp(trace, tstamp, fp);
1074
1075 return fprintf(fp, " ? ");
1076}
1077
Namhyung Kimf15eb532012-10-05 14:02:16 +09001078static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001079static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001080
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001081static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001082{
1083 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001084 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001085}
1086
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001087static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001088 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001089{
1090 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001091 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001092
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001093 if (trace->multiple_threads) {
1094 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001095 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001096 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001097 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001098
1099 return printed;
1100}
1101
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001102static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001103 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001104{
1105 int ret = 0;
1106
1107 switch (event->header.type) {
1108 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001109 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001110 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001111 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001112 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001113 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001114 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001115 break;
1116 }
1117
1118 return ret;
1119}
1120
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001121static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001123 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001124 struct machine *machine)
1125{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001126 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001127 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128}
1129
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001130static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1131{
1132 struct machine *machine = vmachine;
1133
1134 if (machine->kptr_restrict_warned)
1135 return NULL;
1136
1137 if (symbol_conf.kptr_restrict) {
1138 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1139 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1140 "Kernel samples will not be resolved.\n");
1141 machine->kptr_restrict_warned = true;
1142 return NULL;
1143 }
1144
1145 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1146}
1147
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1149{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001150 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001151
1152 if (err)
1153 return err;
1154
David Ahern8fb598e2013-09-28 13:13:00 -06001155 trace->host = machine__new_host();
1156 if (trace->host == NULL)
1157 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001158
Andrei Vagincbd5c172017-11-07 16:22:46 -08001159 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1160 if (err < 0)
1161 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001162
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001163 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001164 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001165 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001166out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001167 if (err)
1168 symbol__exit();
1169
1170 return err;
1171}
1172
Andrei Vagin33974a42017-11-07 16:22:45 -08001173static void trace__symbols__exit(struct trace *trace)
1174{
1175 machine__exit(trace->host);
1176 trace->host = NULL;
1177
1178 symbol__exit();
1179}
1180
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001181static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1182{
1183 int idx;
1184
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001185 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1186 nr_args = sc->fmt->nr_args;
1187
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001188 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1189 if (sc->arg_fmt == NULL)
1190 return -1;
1191
1192 for (idx = 0; idx < nr_args; ++idx) {
1193 if (sc->fmt)
1194 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1195 }
1196
1197 sc->nr_args = nr_args;
1198 return 0;
1199}
1200
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001201static int syscall__set_arg_fmts(struct syscall *sc)
1202{
1203 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001204 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001205
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001206 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001207 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1208 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001209
1210 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001211 (strcmp(field->name, "filename") == 0 ||
1212 strcmp(field->name, "path") == 0 ||
1213 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001214 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001215 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001216 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001217 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001218 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001219 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001220 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001221 else if ((strcmp(field->type, "int") == 0 ||
1222 strcmp(field->type, "unsigned int") == 0 ||
1223 strcmp(field->type, "long") == 0) &&
1224 (len = strlen(field->name)) >= 2 &&
1225 strcmp(field->name + len - 2, "fd") == 0) {
1226 /*
1227 * /sys/kernel/tracing/events/syscalls/sys_enter*
1228 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1229 * 65 int
1230 * 23 unsigned int
1231 * 7 unsigned long
1232 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001233 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001234 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001235 }
1236
1237 return 0;
1238}
1239
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001240static int trace__read_syscall_info(struct trace *trace, int id)
1241{
1242 char tp_name[128];
1243 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001244 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001245
1246 if (name == NULL)
1247 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001248
1249 if (id > trace->syscalls.max) {
1250 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1251
1252 if (nsyscalls == NULL)
1253 return -1;
1254
1255 if (trace->syscalls.max != -1) {
1256 memset(nsyscalls + trace->syscalls.max + 1, 0,
1257 (id - trace->syscalls.max) * sizeof(*sc));
1258 } else {
1259 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1260 }
1261
1262 trace->syscalls.table = nsyscalls;
1263 trace->syscalls.max = id;
1264 }
1265
1266 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001267 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001268
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001269 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001270
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001271 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001272 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001273
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001274 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001275 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001276 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001277 }
1278
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001279 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1280 return -1;
1281
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001282 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001283 return -1;
1284
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001285 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001286 /*
1287 * We need to check and discard the first variable '__syscall_nr'
1288 * or 'nr' that mean the syscall number. It is needless here.
1289 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1290 */
1291 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001292 sc->args = sc->args->next;
1293 --sc->nr_args;
1294 }
1295
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001296 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1297
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001298 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001299}
1300
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001301static int trace__validate_ev_qualifier(struct trace *trace)
1302{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001303 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001304 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001305 struct str_node *pos;
1306
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001307 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1308 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1309 sizeof(trace->ev_qualifier_ids.entries[0]));
1310
1311 if (trace->ev_qualifier_ids.entries == NULL) {
1312 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1313 trace->output);
1314 err = -EINVAL;
1315 goto out;
1316 }
1317
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001318 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001319 i = 0;
1320
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001321 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001322 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001323 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001324
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001325 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001326 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1327 if (id >= 0)
1328 goto matches;
1329
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001330 if (err == 0) {
1331 fputs("Error:\tInvalid syscall ", trace->output);
1332 err = -EINVAL;
1333 } else {
1334 fputs(", ", trace->output);
1335 }
1336
1337 fputs(sc, trace->output);
1338 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001339matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001340 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001341 if (match_next == -1)
1342 continue;
1343
1344 while (1) {
1345 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1346 if (id < 0)
1347 break;
1348 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1349 void *entries;
1350
1351 nr_allocated += 8;
1352 entries = realloc(trace->ev_qualifier_ids.entries,
1353 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1354 if (entries == NULL) {
1355 err = -ENOMEM;
1356 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1357 goto out_free;
1358 }
1359 trace->ev_qualifier_ids.entries = entries;
1360 }
1361 trace->ev_qualifier_ids.nr++;
1362 trace->ev_qualifier_ids.entries[i++] = id;
1363 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001364 }
1365
1366 if (err < 0) {
1367 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1368 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001369out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001370 zfree(&trace->ev_qualifier_ids.entries);
1371 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001372 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001373out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001374 return err;
1375}
1376
David Ahern55d43bca2015-02-19 15:00:22 -05001377/*
1378 * args is to be interpreted as a series of longs but we need to handle
1379 * 8-byte unaligned accesses. args points to raw_data within the event
1380 * and raw_data is guaranteed to be 8-byte unaligned because it is
1381 * preceded by raw_size which is a u32. So we need to copy args to a temp
1382 * variable to read it. Most notably this avoids extended load instructions
1383 * on unaligned addresses
1384 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001385unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001386{
1387 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001388 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001389
1390 memcpy(&val, p, sizeof(val));
1391 return val;
1392}
1393
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001394static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1395 struct syscall_arg *arg)
1396{
1397 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1398 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1399
1400 return scnprintf(bf, size, "arg%d: ", arg->idx);
1401}
1402
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001403static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1404 struct syscall_arg *arg, unsigned long val)
1405{
1406 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1407 arg->val = val;
1408 if (sc->arg_fmt[arg->idx].parm)
1409 arg->parm = sc->arg_fmt[arg->idx].parm;
1410 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1411 }
1412 return scnprintf(bf, size, "%ld", val);
1413}
1414
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001415static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001416 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001417 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001418{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001419 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001420 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001421 u8 bit = 1;
1422 struct syscall_arg arg = {
1423 .args = args,
1424 .idx = 0,
1425 .mask = 0,
1426 .trace = trace,
1427 .thread = thread,
1428 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001429 struct thread_trace *ttrace = thread__priv(thread);
1430
1431 /*
1432 * Things like fcntl will set this in its 'cmd' formatter to pick the
1433 * right formatter for the return value (an fd? file flags?), which is
1434 * not needed for syscalls that always return a given type, say an fd.
1435 */
1436 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001437
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001438 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001439 struct format_field *field;
1440
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001441 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001442 field = field->next, ++arg.idx, bit <<= 1) {
1443 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001444 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001445
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001446 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001447
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001448 /*
1449 * Suppress this argument if its value is zero and
1450 * and we don't have a string associated in an
1451 * strarray for it.
1452 */
David Ahern55d43bca2015-02-19 15:00:22 -05001453 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001454 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001455 (sc->arg_fmt[arg.idx].show_zero ||
1456 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001457 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1458 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001459 continue;
1460
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001461 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001462 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001463 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001464 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001465 } else if (IS_ERR(sc->tp_format)) {
1466 /*
1467 * If we managed to read the tracepoint /format file, then we
1468 * may end up not having any args, like with gettid(), so only
1469 * print the raw args when we didn't manage to read it.
1470 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001471 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001472 if (arg.mask & bit)
1473 goto next_arg;
1474 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001475 if (printed)
1476 printed += scnprintf(bf + printed, size - printed, ", ");
1477 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001478 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1479next_arg:
1480 ++arg.idx;
1481 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001482 }
1483 }
1484
1485 return printed;
1486}
1487
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001488typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001489 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001490 struct perf_sample *sample);
1491
1492static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001493 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001494{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001495
1496 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001497
1498 /*
1499 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1500 * before that, leaving at a higher verbosity level till that is
1501 * explained. Reproduced with plain ftrace with:
1502 *
1503 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1504 * grep "NR -1 " /t/trace_pipe
1505 *
1506 * After generating some load on the machine.
1507 */
1508 if (verbose > 1) {
1509 static u64 n;
1510 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1511 id, perf_evsel__name(evsel), ++n);
1512 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001513 return NULL;
1514 }
1515
1516 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1517 trace__read_syscall_info(trace, id))
1518 goto out_cant_read;
1519
1520 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1521 goto out_cant_read;
1522
1523 return &trace->syscalls.table[id];
1524
1525out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001526 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001527 fprintf(trace->output, "Problems reading syscall %d", id);
1528 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1529 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1530 fputs(" information\n", trace->output);
1531 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001532 return NULL;
1533}
1534
David Ahernbf2575c2013-10-08 21:26:53 -06001535static void thread__update_stats(struct thread_trace *ttrace,
1536 int id, struct perf_sample *sample)
1537{
1538 struct int_node *inode;
1539 struct stats *stats;
1540 u64 duration = 0;
1541
1542 inode = intlist__findnew(ttrace->syscall_stats, id);
1543 if (inode == NULL)
1544 return;
1545
1546 stats = inode->priv;
1547 if (stats == NULL) {
1548 stats = malloc(sizeof(struct stats));
1549 if (stats == NULL)
1550 return;
1551 init_stats(stats);
1552 inode->priv = stats;
1553 }
1554
1555 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1556 duration = sample->time - ttrace->entry_time;
1557
1558 update_stats(stats, duration);
1559}
1560
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001561static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001562{
1563 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001564 size_t printed;
1565
1566 if (trace->current == NULL)
1567 return 0;
1568
1569 ttrace = thread__priv(trace->current);
1570
1571 if (!ttrace->entry_pending)
1572 return 0;
1573
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001574 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001575 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1576 ttrace->entry_pending = false;
1577
1578 return printed;
1579}
1580
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001581static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1582 struct perf_sample *sample, struct thread *thread)
1583{
1584 int printed = 0;
1585
1586 if (trace->print_sample) {
1587 double ts = (double)sample->time / NSEC_PER_MSEC;
1588
1589 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1590 perf_evsel__name(evsel), ts,
1591 thread__comm_str(thread),
1592 sample->pid, sample->tid, sample->cpu);
1593 }
1594
1595 return printed;
1596}
1597
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001598static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001599 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001600 struct perf_sample *sample)
1601{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001602 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001603 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001604 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001605 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001606 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001607 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001608 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001609
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001610 if (sc == NULL)
1611 return -1;
1612
David Ahern8fb598e2013-09-28 13:13:00 -06001613 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001614 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001615 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001616 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001617
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001618 trace__fprintf_sample(trace, evsel, sample, thread);
1619
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001620 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001621
1622 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001623 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001624 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001625 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001626 }
1627
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001628 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001629 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001630
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001631 ttrace->entry_time = sample->time;
1632 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001633 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001634
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001635 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001636 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001637
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001638 if (sc->is_exit) {
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001639 if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001640 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001641 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001642 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001643 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001644 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001645 /* See trace__vfs_getname & trace__sys_exit */
1646 ttrace->filename.pending_open = false;
1647 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001648
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001649 if (trace->current != thread) {
1650 thread__put(trace->current);
1651 trace->current = thread__get(thread);
1652 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001653 err = 0;
1654out_put:
1655 thread__put(thread);
1656 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001657}
1658
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001659static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1660 struct perf_sample *sample,
1661 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001662{
1663 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301664 int max_stack = evsel->attr.sample_max_stack ?
1665 evsel->attr.sample_max_stack :
1666 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001667
1668 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301669 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001670 return -1;
1671
1672 return 0;
1673}
1674
1675static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1676{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001677 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001678 const unsigned int print_opts = EVSEL__PRINT_SYM |
1679 EVSEL__PRINT_DSO |
1680 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001681
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001682 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001683}
1684
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001685static const char *errno_to_name(struct perf_evsel *evsel, int err)
1686{
1687 struct perf_env *env = perf_evsel__env(evsel);
1688 const char *arch_name = perf_env__arch(env);
1689
1690 return arch_syscalls__strerrno(arch_name, err);
1691}
1692
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001693static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001694 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001695 struct perf_sample *sample)
1696{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001697 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001698 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001699 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001700 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001701 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001702 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001703 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001704
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001705 if (sc == NULL)
1706 return -1;
1707
David Ahern8fb598e2013-09-28 13:13:00 -06001708 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001709 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001710 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001711 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001712
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001713 trace__fprintf_sample(trace, evsel, sample, thread);
1714
David Ahernbf2575c2013-10-08 21:26:53 -06001715 if (trace->summary)
1716 thread__update_stats(ttrace, id, sample);
1717
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001718 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001719
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001720 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001721 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1722 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001723 ++trace->stats.vfs_getname;
1724 }
1725
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001726 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001727 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001728 if (trace__filter_duration(trace, duration))
1729 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001730 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001731 } else if (trace->duration_filter)
1732 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001733
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001734 if (sample->callchain) {
1735 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1736 if (callchain_ret == 0) {
1737 if (callchain_cursor.nr < trace->min_stack)
1738 goto out;
1739 callchain_ret = 1;
1740 }
1741 }
1742
David Ahernfd2eaba2013-11-12 09:31:15 -07001743 if (trace->summary_only)
1744 goto out;
1745
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001746 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001747
1748 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001749 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001750 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001751 fprintf(trace->output, " ... [");
1752 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1753 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001754 }
1755
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001756 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001757 if (ret < 0)
1758 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001759signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001760 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001761 } else if (ret < 0) {
1762errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001763 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001764 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001765 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001766
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001767 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001768 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001769 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001770 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001771 else if (ttrace->ret_scnprintf) {
1772 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001773 struct syscall_arg arg = {
1774 .val = ret,
1775 .thread = thread,
1776 .trace = trace,
1777 };
1778 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001779 ttrace->ret_scnprintf = NULL;
1780 fprintf(trace->output, ") = %s", bf);
1781 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001782 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001783 else if (sc->fmt->errpid) {
1784 struct thread *child = machine__find_thread(trace->host, ret, ret);
1785
1786 if (child != NULL) {
1787 fprintf(trace->output, ") = %ld", ret);
1788 if (child->comm_set)
1789 fprintf(trace->output, " (%s)", thread__comm_str(child));
1790 thread__put(child);
1791 }
1792 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001793 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001794
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001795 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001796
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001797 if (callchain_ret > 0)
1798 trace__fprintf_callchain(trace, sample);
1799 else if (callchain_ret < 0)
1800 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001801out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001802 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001803 err = 0;
1804out_put:
1805 thread__put(thread);
1806 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001807}
1808
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001809static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001810 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001811 struct perf_sample *sample)
1812{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001813 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1814 struct thread_trace *ttrace;
1815 size_t filename_len, entry_str_len, to_move;
1816 ssize_t remaining_space;
1817 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001818 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001819
1820 if (!thread)
1821 goto out;
1822
1823 ttrace = thread__priv(thread);
1824 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001825 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001826
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001827 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001828 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001829 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001830
1831 if (ttrace->filename.namelen < filename_len) {
1832 char *f = realloc(ttrace->filename.name, filename_len + 1);
1833
1834 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001835 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001836
1837 ttrace->filename.namelen = filename_len;
1838 ttrace->filename.name = f;
1839 }
1840
1841 strcpy(ttrace->filename.name, filename);
1842 ttrace->filename.pending_open = true;
1843
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001844 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001845 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001846
1847 entry_str_len = strlen(ttrace->entry_str);
1848 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1849 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001850 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001851
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001852 if (filename_len > (size_t)remaining_space) {
1853 filename += filename_len - remaining_space;
1854 filename_len = remaining_space;
1855 }
1856
1857 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1858 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1859 memmove(pos + filename_len, pos, to_move);
1860 memcpy(pos, filename, filename_len);
1861
1862 ttrace->filename.ptr = 0;
1863 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001864out_put:
1865 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001866out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001867 return 0;
1868}
1869
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001870static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001871 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001872 struct perf_sample *sample)
1873{
1874 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1875 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001876 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001877 sample->pid,
1878 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001879 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001880
1881 if (ttrace == NULL)
1882 goto out_dump;
1883
1884 ttrace->runtime_ms += runtime_ms;
1885 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001886out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001887 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001888 return 0;
1889
1890out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001891 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001892 evsel->name,
1893 perf_evsel__strval(evsel, sample, "comm"),
1894 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1895 runtime,
1896 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001897 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001898}
1899
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001900static int bpf_output__printer(enum binary_printer_ops op,
1901 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001902{
Wang Nan1d6c9402016-02-26 09:31:55 +00001903 unsigned char ch = (unsigned char)val;
1904
1905 switch (op) {
1906 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001907 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001908 case BINARY_PRINT_DATA_BEGIN:
1909 case BINARY_PRINT_LINE_BEGIN:
1910 case BINARY_PRINT_ADDR:
1911 case BINARY_PRINT_NUM_DATA:
1912 case BINARY_PRINT_NUM_PAD:
1913 case BINARY_PRINT_SEP:
1914 case BINARY_PRINT_CHAR_PAD:
1915 case BINARY_PRINT_LINE_END:
1916 case BINARY_PRINT_DATA_END:
1917 default:
1918 break;
1919 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001920
1921 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001922}
1923
1924static void bpf_output__fprintf(struct trace *trace,
1925 struct perf_sample *sample)
1926{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001927 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1928 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001929}
1930
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001931static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1932 union perf_event *event __maybe_unused,
1933 struct perf_sample *sample)
1934{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001935 int callchain_ret = 0;
1936
1937 if (sample->callchain) {
1938 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1939 if (callchain_ret == 0) {
1940 if (callchain_cursor.nr < trace->min_stack)
1941 goto out;
1942 callchain_ret = 1;
1943 }
1944 }
1945
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001946 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001947 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001948
1949 if (trace->trace_syscalls)
1950 fprintf(trace->output, "( ): ");
1951
1952 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001953
Wang Nan1d6c9402016-02-26 09:31:55 +00001954 if (perf_evsel__is_bpf_output(evsel)) {
1955 bpf_output__fprintf(trace, sample);
1956 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001957 event_format__fprintf(evsel->tp_format, sample->cpu,
1958 sample->raw_data, sample->raw_size,
1959 trace->output);
1960 }
1961
1962 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001963
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001964 if (callchain_ret > 0)
1965 trace__fprintf_callchain(trace, sample);
1966 else if (callchain_ret < 0)
1967 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1968out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001969 return 0;
1970}
1971
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001972static void print_location(FILE *f, struct perf_sample *sample,
1973 struct addr_location *al,
1974 bool print_dso, bool print_sym)
1975{
1976
Namhyung Kimbb963e12017-02-17 17:17:38 +09001977 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001978 fprintf(f, "%s@", al->map->dso->long_name);
1979
Namhyung Kimbb963e12017-02-17 17:17:38 +09001980 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001981 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001982 al->addr - al->sym->start);
1983 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001984 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001985 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001986 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001987}
1988
1989static int trace__pgfault(struct trace *trace,
1990 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001991 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001992 struct perf_sample *sample)
1993{
1994 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001995 struct addr_location al;
1996 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001997 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001998 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001999 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002000
2001 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002002
2003 if (sample->callchain) {
2004 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2005 if (callchain_ret == 0) {
2006 if (callchain_cursor.nr < trace->min_stack)
2007 goto out_put;
2008 callchain_ret = 1;
2009 }
2010 }
2011
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002012 ttrace = thread__trace(thread, trace->output);
2013 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002014 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002015
2016 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2017 ttrace->pfmaj++;
2018 else
2019 ttrace->pfmin++;
2020
2021 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002022 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002023
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002024 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002025 sample->ip, &al);
2026
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002027 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002028
2029 fprintf(trace->output, "%sfault [",
2030 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2031 "maj" : "min");
2032
2033 print_location(trace->output, sample, &al, false, true);
2034
2035 fprintf(trace->output, "] => ");
2036
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002037 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002038 sample->addr, &al);
2039
2040 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002041 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002042 MAP__FUNCTION, sample->addr, &al);
2043
2044 if (al.map)
2045 map_type = 'x';
2046 else
2047 map_type = '?';
2048 }
2049
2050 print_location(trace->output, sample, &al, true, false);
2051
2052 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002053
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002054 if (callchain_ret > 0)
2055 trace__fprintf_callchain(trace, sample);
2056 else if (callchain_ret < 0)
2057 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002058out:
2059 err = 0;
2060out_put:
2061 thread__put(thread);
2062 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002063}
2064
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002065static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002066 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002067 struct perf_sample *sample)
2068{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002069 /*
2070 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2071 * and don't use sample->time unconditionally, we may end up having
2072 * some other event in the future without PERF_SAMPLE_TIME for good
2073 * reason, i.e. we may not be interested in its timestamps, just in
2074 * it taking place, picking some piece of information when it
2075 * appears in our event stream (vfs_getname comes to mind).
2076 */
2077 if (trace->base_time == 0 && !trace->full_time &&
2078 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002079 trace->base_time = sample->time;
2080}
2081
David Ahern6810fc92013-08-28 22:29:52 -06002082static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002083 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002084 struct perf_sample *sample,
2085 struct perf_evsel *evsel,
2086 struct machine *machine __maybe_unused)
2087{
2088 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002089 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002090 int err = 0;
2091
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002092 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002093
David Ahernaa07df62016-11-25 09:29:52 -07002094 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2095 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002096 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002097
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002098 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002099
David Ahern31605652013-12-04 19:41:41 -07002100 if (handler) {
2101 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002102 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002103 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002104out:
2105 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002106 return err;
2107}
2108
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002109static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002110{
2111 unsigned int rec_argc, i, j;
2112 const char **rec_argv;
2113 const char * const record_args[] = {
2114 "record",
2115 "-R",
2116 "-m", "1024",
2117 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002118 };
2119
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002120 const char * const sc_args[] = { "-e", };
2121 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2122 const char * const majpf_args[] = { "-e", "major-faults" };
2123 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2124 const char * const minpf_args[] = { "-e", "minor-faults" };
2125 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2126
David Ahern9aca7f12013-12-04 19:41:39 -07002127 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002128 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2129 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002130 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2131
2132 if (rec_argv == NULL)
2133 return -ENOMEM;
2134
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002135 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002136 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002137 rec_argv[j++] = record_args[i];
2138
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002139 if (trace->trace_syscalls) {
2140 for (i = 0; i < sc_args_nr; i++)
2141 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002142
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002143 /* event string may be different for older kernels - e.g., RHEL6 */
2144 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2145 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2146 else if (is_valid_tracepoint("syscalls:sys_enter"))
2147 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2148 else {
2149 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002150 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002151 return -1;
2152 }
David Ahern9aca7f12013-12-04 19:41:39 -07002153 }
David Ahern9aca7f12013-12-04 19:41:39 -07002154
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002155 if (trace->trace_pgfaults & TRACE_PFMAJ)
2156 for (i = 0; i < majpf_args_nr; i++)
2157 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002158
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002159 if (trace->trace_pgfaults & TRACE_PFMIN)
2160 for (i = 0; i < minpf_args_nr; i++)
2161 rec_argv[j++] = minpf_args[i];
2162
2163 for (i = 0; i < (unsigned int)argc; i++)
2164 rec_argv[j++] = argv[i];
2165
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002166 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002167}
2168
David Ahernbf2575c2013-10-08 21:26:53 -06002169static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2170
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002171static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002172{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002173 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002174
2175 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002176 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002177
2178 if (perf_evsel__field(evsel, "pathname") == NULL) {
2179 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002180 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002181 }
2182
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002183 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002184 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002185 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002186}
2187
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002188static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002189{
2190 struct perf_evsel *evsel;
2191 struct perf_event_attr attr = {
2192 .type = PERF_TYPE_SOFTWARE,
2193 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002194 };
2195
2196 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002197 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002198
2199 event_attr_init(&attr);
2200
2201 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002202 if (evsel)
2203 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002204
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002205 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002206}
2207
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002208static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2209{
2210 const u32 type = event->header.type;
2211 struct perf_evsel *evsel;
2212
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002213 if (type != PERF_RECORD_SAMPLE) {
2214 trace__process_event(trace, trace->host, event, sample);
2215 return;
2216 }
2217
2218 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2219 if (evsel == NULL) {
2220 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2221 return;
2222 }
2223
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002224 trace__set_base_time(trace, evsel, sample);
2225
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002226 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2227 sample->raw_data == NULL) {
2228 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2229 perf_evsel__name(evsel), sample->tid,
2230 sample->cpu, sample->raw_size);
2231 } else {
2232 tracepoint_handler handler = evsel->handler;
2233 handler(trace, evsel, event, sample);
2234 }
2235}
2236
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002237static int trace__add_syscall_newtp(struct trace *trace)
2238{
2239 int ret = -1;
2240 struct perf_evlist *evlist = trace->evlist;
2241 struct perf_evsel *sys_enter, *sys_exit;
2242
2243 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2244 if (sys_enter == NULL)
2245 goto out;
2246
2247 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2248 goto out_delete_sys_enter;
2249
2250 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2251 if (sys_exit == NULL)
2252 goto out_delete_sys_enter;
2253
2254 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2255 goto out_delete_sys_exit;
2256
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002257 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2258 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2259
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002260 perf_evlist__add(evlist, sys_enter);
2261 perf_evlist__add(evlist, sys_exit);
2262
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002263 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002264 /*
2265 * We're interested only in the user space callchain
2266 * leading to the syscall, allow overriding that for
2267 * debugging reasons using --kernel_syscall_callchains
2268 */
2269 sys_exit->attr.exclude_callchain_kernel = 1;
2270 }
2271
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002272 trace->syscalls.events.sys_enter = sys_enter;
2273 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002274
2275 ret = 0;
2276out:
2277 return ret;
2278
2279out_delete_sys_exit:
2280 perf_evsel__delete_priv(sys_exit);
2281out_delete_sys_enter:
2282 perf_evsel__delete_priv(sys_enter);
2283 goto out;
2284}
2285
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002286static int trace__set_ev_qualifier_filter(struct trace *trace)
2287{
2288 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002289 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002290 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2291 trace->ev_qualifier_ids.nr,
2292 trace->ev_qualifier_ids.entries);
2293
2294 if (filter == NULL)
2295 goto out_enomem;
2296
Mathieu Poirier3541c032016-09-16 08:44:04 -06002297 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2298 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002299 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002300 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002301 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002302
2303 free(filter);
2304out:
2305 return err;
2306out_enomem:
2307 errno = ENOMEM;
2308 goto out;
2309}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002310
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002311static int trace__set_filter_loop_pids(struct trace *trace)
2312{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002313 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002314 pid_t pids[32] = {
2315 getpid(),
2316 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002317 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2318
2319 while (thread && nr < ARRAY_SIZE(pids)) {
2320 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2321
2322 if (parent == NULL)
2323 break;
2324
2325 if (!strcmp(thread__comm_str(parent), "sshd")) {
2326 pids[nr++] = parent->tid;
2327 break;
2328 }
2329 thread = parent;
2330 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002331
2332 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2333}
2334
Namhyung Kimf15eb532012-10-05 14:02:16 +09002335static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002336{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002337 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002338 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002339 int err = -1, i;
2340 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002341 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002342 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002343
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002344 trace->live = true;
2345
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002346 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002347 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002348
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002349 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002350 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002351
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002352 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2353 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2354 if (pgfault_maj == NULL)
2355 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002356 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002357 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002358 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002359
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002360 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2361 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2362 if (pgfault_min == NULL)
2363 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002364 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002365 perf_evlist__add(evlist, pgfault_min);
2366 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002367
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002368 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002369 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2370 trace__sched_stat_runtime))
2371 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002372
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002373 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2374 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002375 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002376 goto out_delete_evlist;
2377 }
2378
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002379 err = trace__symbols_init(trace, evlist);
2380 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002381 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002382 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002383 }
2384
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002385 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002386
Namhyung Kimf15eb532012-10-05 14:02:16 +09002387 signal(SIGCHLD, sig_handler);
2388 signal(SIGINT, sig_handler);
2389
2390 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002391 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002392 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002393 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002394 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002395 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002396 }
2397 }
2398
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002399 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002400 if (err < 0)
2401 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002402
Wang Nanba504232016-02-26 09:31:54 +00002403 err = bpf__apply_obj_config();
2404 if (err) {
2405 char errbuf[BUFSIZ];
2406
2407 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2408 pr_err("ERROR: Apply config to BPF failed: %s\n",
2409 errbuf);
2410 goto out_error_open;
2411 }
2412
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002413 /*
2414 * Better not use !target__has_task() here because we need to cover the
2415 * case where no threads were specified in the command line, but a
2416 * workload was, and in that case we will fill in the thread_map when
2417 * we fork the workload in perf_evlist__prepare_workload.
2418 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002419 if (trace->filter_pids.nr > 0)
2420 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002421 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002422 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002423
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002424 if (err < 0)
2425 goto out_error_mem;
2426
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002427 if (trace->ev_qualifier_ids.nr > 0) {
2428 err = trace__set_ev_qualifier_filter(trace);
2429 if (err < 0)
2430 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002431
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002432 pr_debug("event qualifier tracepoint filter: %s\n",
2433 trace->syscalls.events.sys_exit->filter);
2434 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002435
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002436 err = perf_evlist__apply_filters(evlist, &evsel);
2437 if (err < 0)
2438 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002439
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002440 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002441 if (err < 0)
2442 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002443
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002444 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002445 perf_evlist__enable(evlist);
2446
Namhyung Kimf15eb532012-10-05 14:02:16 +09002447 if (forks)
2448 perf_evlist__start_workload(evlist);
2449
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002450 if (trace->opts.initial_delay) {
2451 usleep(trace->opts.initial_delay * 1000);
2452 perf_evlist__enable(evlist);
2453 }
2454
Jiri Olsae13798c2015-06-23 00:36:02 +02002455 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002456 evlist->threads->nr > 1 ||
2457 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002458
2459 /*
2460 * Now that we already used evsel->attr to ask the kernel to setup the
2461 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2462 * trace__resolve_callchain(), allowing per-event max-stack settings
2463 * to override an explicitely set --max-stack global setting.
2464 */
2465 evlist__for_each_entry(evlist, evsel) {
2466 if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) &&
2467 evsel->attr.sample_max_stack == 0)
2468 evsel->attr.sample_max_stack = trace->max_stack;
2469 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002470again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002471 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002472
2473 for (i = 0; i < evlist->nr_mmaps; i++) {
2474 union perf_event *event;
2475
2476 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002478
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002479 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002480
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002481 err = perf_evlist__parse_sample(evlist, event, &sample);
2482 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002483 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002484 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002485 }
2486
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002487 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002488next_event:
2489 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002490
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002491 if (interrupted)
2492 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002493
2494 if (done && !draining) {
2495 perf_evlist__disable(evlist);
2496 draining = true;
2497 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002498 }
2499 }
2500
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002501 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002502 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002503
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002504 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2505 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2506 draining = true;
2507
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002508 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002509 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002510 } else {
2511 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002512 }
2513
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002514out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002515 thread__zput(trace->current);
2516
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002517 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002518
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002519 if (!err) {
2520 if (trace->summary)
2521 trace__fprintf_thread_summary(trace, trace->output);
2522
2523 if (trace->show_tool_stats) {
2524 fprintf(trace->output, "Stats:\n "
2525 " vfs_getname : %" PRIu64 "\n"
2526 " proc_getname: %" PRIu64 "\n",
2527 trace->stats.vfs_getname,
2528 trace->stats.proc_getname);
2529 }
2530 }
David Ahernbf2575c2013-10-08 21:26:53 -06002531
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002532out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002533 trace__symbols__exit(trace);
2534
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002535 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002536 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002537 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002538 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002539{
2540 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002541
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002542out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002543 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002544 goto out_error;
2545
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002546out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002547 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002548 goto out_error;
2549
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002550out_error_mmap:
2551 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2552 goto out_error;
2553
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002554out_error_open:
2555 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2556
2557out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002558 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302559 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002560
2561out_error_apply_filters:
2562 fprintf(trace->output,
2563 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2564 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002565 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002566 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002567}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002568out_error_mem:
2569 fprintf(trace->output, "Not enough memory to run!\n");
2570 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002571
2572out_errno:
2573 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2574 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002575}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002576
David Ahern6810fc92013-08-28 22:29:52 -06002577static int trace__replay(struct trace *trace)
2578{
2579 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002580 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002581 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002582 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002583 .file = {
2584 .path = input_name,
2585 },
2586 .mode = PERF_DATA_MODE_READ,
2587 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002588 };
David Ahern6810fc92013-08-28 22:29:52 -06002589 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002590 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002591 int err = -1;
2592
2593 trace->tool.sample = trace__process_sample;
2594 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002595 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002596 trace->tool.comm = perf_event__process_comm;
2597 trace->tool.exit = perf_event__process_exit;
2598 trace->tool.fork = perf_event__process_fork;
2599 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302600 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002601 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302602 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002603
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002604 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002605 trace->tool.ordering_requires_timestamps = true;
2606
2607 /* add tid to output */
2608 trace->multiple_threads = true;
2609
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002610 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002611 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002612 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002613
David Ahernaa07df62016-11-25 09:29:52 -07002614 if (trace->opts.target.pid)
2615 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2616
2617 if (trace->opts.target.tid)
2618 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2619
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002620 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002621 goto out;
2622
David Ahern8fb598e2013-09-28 13:13:00 -06002623 trace->host = &session->machines.host;
2624
David Ahern6810fc92013-08-28 22:29:52 -06002625 err = perf_session__set_tracepoints_handlers(session, handlers);
2626 if (err)
2627 goto out;
2628
Namhyung Kim003824e2013-11-12 15:25:00 +09002629 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2630 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002631 /* older kernels have syscalls tp versus raw_syscalls */
2632 if (evsel == NULL)
2633 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2634 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002635
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002636 if (evsel &&
2637 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2638 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002639 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2640 goto out;
2641 }
2642
2643 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2644 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002645 if (evsel == NULL)
2646 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2647 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002648 if (evsel &&
2649 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2650 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002651 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002652 goto out;
2653 }
2654
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002655 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002656 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2657 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2658 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2659 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2660 evsel->handler = trace__pgfault;
2661 }
2662
David Ahern6810fc92013-08-28 22:29:52 -06002663 setup_pager();
2664
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002665 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002666 if (err)
2667 pr_err("Failed to process events, error %d", err);
2668
David Ahernbf2575c2013-10-08 21:26:53 -06002669 else if (trace->summary)
2670 trace__fprintf_thread_summary(trace, trace->output);
2671
David Ahern6810fc92013-08-28 22:29:52 -06002672out:
2673 perf_session__delete(session);
2674
2675 return err;
2676}
2677
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002678static size_t trace__fprintf_threads_header(FILE *fp)
2679{
2680 size_t printed;
2681
Pekka Enberg99ff7152013-11-12 16:42:14 +02002682 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002683
2684 return printed;
2685}
2686
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002687DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2688 struct stats *stats;
2689 double msecs;
2690 int syscall;
2691)
2692{
2693 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2694 struct stats *stats = source->priv;
2695
2696 entry->syscall = source->i;
2697 entry->stats = stats;
2698 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2699}
2700
David Ahernbf2575c2013-10-08 21:26:53 -06002701static size_t thread__dump_stats(struct thread_trace *ttrace,
2702 struct trace *trace, FILE *fp)
2703{
David Ahernbf2575c2013-10-08 21:26:53 -06002704 size_t printed = 0;
2705 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002706 struct rb_node *nd;
2707 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002708
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002709 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002710 return 0;
2711
2712 printed += fprintf(fp, "\n");
2713
Milian Wolff834fd462015-08-06 11:24:29 +02002714 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2715 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2716 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002717
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002718 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002719 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002720 if (stats) {
2721 double min = (double)(stats->min) / NSEC_PER_MSEC;
2722 double max = (double)(stats->max) / NSEC_PER_MSEC;
2723 double avg = avg_stats(stats);
2724 double pct;
2725 u64 n = (u64) stats->n;
2726
2727 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2728 avg /= NSEC_PER_MSEC;
2729
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002730 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002731 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002732 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002733 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002734 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002735 }
David Ahernbf2575c2013-10-08 21:26:53 -06002736 }
2737
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002738 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002739 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002740
2741 return printed;
2742}
2743
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002744static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002745{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002746 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002747 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002748 double ratio;
2749
2750 if (ttrace == NULL)
2751 return 0;
2752
2753 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2754
Pekka Enberg15e65c62013-11-14 18:43:30 +02002755 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002756 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002757 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002758 if (ttrace->pfmaj)
2759 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2760 if (ttrace->pfmin)
2761 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002762 if (trace->sched)
2763 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2764 else if (fputc('\n', fp) != EOF)
2765 ++printed;
2766
David Ahernbf2575c2013-10-08 21:26:53 -06002767 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002768
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002769 return printed;
2770}
David Ahern896cbb52013-09-28 13:12:59 -06002771
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002772static unsigned long thread__nr_events(struct thread_trace *ttrace)
2773{
2774 return ttrace ? ttrace->nr_events : 0;
2775}
2776
2777DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2778 struct thread *thread;
2779)
2780{
2781 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002782}
2783
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002784static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2785{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002786 size_t printed = trace__fprintf_threads_header(fp);
2787 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002788 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002789
Kan Liang91e467b2017-09-10 19:23:14 -07002790 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2791 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2792
2793 if (threads == NULL) {
2794 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2795 return 0;
2796 }
2797
2798 resort_rb__for_each_entry(nd, threads)
2799 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2800
2801 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002802 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002803 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002804}
2805
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002806static int trace__set_duration(const struct option *opt, const char *str,
2807 int unset __maybe_unused)
2808{
2809 struct trace *trace = opt->value;
2810
2811 trace->duration_filter = atof(str);
2812 return 0;
2813}
2814
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002815static int trace__set_filter_pids(const struct option *opt, const char *str,
2816 int unset __maybe_unused)
2817{
2818 int ret = -1;
2819 size_t i;
2820 struct trace *trace = opt->value;
2821 /*
2822 * FIXME: introduce a intarray class, plain parse csv and create a
2823 * { int nr, int entries[] } struct...
2824 */
2825 struct intlist *list = intlist__new(str);
2826
2827 if (list == NULL)
2828 return -1;
2829
2830 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2831 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2832
2833 if (trace->filter_pids.entries == NULL)
2834 goto out;
2835
2836 trace->filter_pids.entries[0] = getpid();
2837
2838 for (i = 1; i < trace->filter_pids.nr; ++i)
2839 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2840
2841 intlist__delete(list);
2842 ret = 0;
2843out:
2844 return ret;
2845}
2846
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002847static int trace__open_output(struct trace *trace, const char *filename)
2848{
2849 struct stat st;
2850
2851 if (!stat(filename, &st) && st.st_size) {
2852 char oldname[PATH_MAX];
2853
2854 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2855 unlink(oldname);
2856 rename(filename, oldname);
2857 }
2858
2859 trace->output = fopen(filename, "w");
2860
2861 return trace->output == NULL ? -errno : 0;
2862}
2863
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002864static int parse_pagefaults(const struct option *opt, const char *str,
2865 int unset __maybe_unused)
2866{
2867 int *trace_pgfaults = opt->value;
2868
2869 if (strcmp(str, "all") == 0)
2870 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2871 else if (strcmp(str, "maj") == 0)
2872 *trace_pgfaults |= TRACE_PFMAJ;
2873 else if (strcmp(str, "min") == 0)
2874 *trace_pgfaults |= TRACE_PFMIN;
2875 else
2876 return -1;
2877
2878 return 0;
2879}
2880
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002881static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2882{
2883 struct perf_evsel *evsel;
2884
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002885 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002886 evsel->handler = handler;
2887}
2888
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002889/*
2890 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2891 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2892 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2893 *
2894 * It'd be better to introduce a parse_options() variant that would return a
2895 * list with the terms it didn't match to an event...
2896 */
2897static int trace__parse_events_option(const struct option *opt, const char *str,
2898 int unset __maybe_unused)
2899{
2900 struct trace *trace = (struct trace *)opt->value;
2901 const char *s = str;
2902 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002903 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002904 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2905 char group_name[PATH_MAX];
2906
2907 if (strace_groups_dir == NULL)
2908 return -1;
2909
2910 if (*s == '!') {
2911 ++s;
2912 trace->not_ev_qualifier = true;
2913 }
2914
2915 while (1) {
2916 if ((sep = strchr(s, ',')) != NULL)
2917 *sep = '\0';
2918
2919 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002920 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
2921 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002922 list = 1;
2923 } else {
2924 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2925 if (access(group_name, R_OK) == 0)
2926 list = 1;
2927 }
2928
2929 if (lists[list]) {
2930 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2931 } else {
2932 lists[list] = malloc(len);
2933 if (lists[list] == NULL)
2934 goto out;
2935 strcpy(lists[list], s);
2936 }
2937
2938 if (!sep)
2939 break;
2940
2941 *sep = ',';
2942 s = sep + 1;
2943 }
2944
2945 if (lists[1] != NULL) {
2946 struct strlist_config slist_config = {
2947 .dirname = strace_groups_dir,
2948 };
2949
2950 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2951 if (trace->ev_qualifier == NULL) {
2952 fputs("Not enough memory to parse event qualifier", trace->output);
2953 goto out;
2954 }
2955
2956 if (trace__validate_ev_qualifier(trace))
2957 goto out;
2958 }
2959
2960 err = 0;
2961
2962 if (lists[0]) {
2963 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2964 "event selector. use 'perf list' to list available events",
2965 parse_events_option);
2966 err = parse_events_option(&o, lists[0], 0);
2967 }
2968out:
2969 if (sep)
2970 *sep = ',';
2971
2972 return err;
2973}
2974
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002975int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002976{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002977 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002978 "perf trace [<options>] [<command>]",
2979 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002980 "perf trace record [<options>] [<command>]",
2981 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002982 NULL
2983 };
2984 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002985 .syscalls = {
2986 . max = -1,
2987 },
2988 .opts = {
2989 .target = {
2990 .uid = UINT_MAX,
2991 .uses_mmap = true,
2992 },
2993 .user_freq = UINT_MAX,
2994 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002995 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002996 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002997 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002998 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002999 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003000 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003001 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003002 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003003 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003004 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003005 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003006 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003007 OPT_CALLBACK('e', "event", &trace, "event",
3008 "event/syscall selector. use 'perf list' to list available events",
3009 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003010 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3011 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003012 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003013 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3014 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003015 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003016 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003017 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3018 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003019 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003020 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003021 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3022 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003023 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003024 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003025 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003026 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003027 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003028 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003029 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3030 "number of mmap data pages",
3031 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003032 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003033 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003034 OPT_CALLBACK(0, "duration", &trace, "float",
3035 "show only events with duration > N.M ms",
3036 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003037 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003038 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003039 OPT_BOOLEAN('T', "time", &trace.full_time,
3040 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003041 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3042 "Show only syscall summary with statistics"),
3043 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3044 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003045 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3046 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003047 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003048 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003049 OPT_CALLBACK(0, "call-graph", &trace.opts,
3050 "record_mode[,record_size]", record_callchain_help,
3051 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003052 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3053 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003054 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3055 "Set the minimum stack depth when parsing the callchain, "
3056 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003057 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3058 "Set the maximum stack depth when parsing the callchain, "
3059 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003060 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003061 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3062 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003063 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3064 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003065 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3066 "ms to wait before starting measurement after program "
3067 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003068 OPT_END()
3069 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003070 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003071 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003072 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003073 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003074 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003075
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003076 signal(SIGSEGV, sighandler_dump_stack);
3077 signal(SIGFPE, sighandler_dump_stack);
3078
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003079 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003080 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003081
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003082 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003083 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003084 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003085 goto out;
3086 }
3087
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003088 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3089 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003090
Wang Nand7888572016-04-08 15:07:24 +00003091 err = bpf__setup_stdout(trace.evlist);
3092 if (err) {
3093 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3094 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3095 goto out;
3096 }
3097
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003098 err = -1;
3099
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003100 if (trace.trace_pgfaults) {
3101 trace.opts.sample_address = true;
3102 trace.opts.sample_time = true;
3103 }
3104
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003105 if (trace.opts.mmap_pages == UINT_MAX)
3106 mmap_pages_user_set = false;
3107
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003108 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003109 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003110 max_stack_user_set = false;
3111 }
3112
3113#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003114 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003115 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003116 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003117#endif
3118
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003119 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003120 if (!mmap_pages_user_set && geteuid() == 0)
3121 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3122
Milian Wolff566a0882016-04-08 13:34:15 +02003123 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003124 }
Milian Wolff566a0882016-04-08 13:34:15 +02003125
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003126 if (trace.evlist->nr_entries > 0)
3127 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3128
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003129 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3130 return trace__record(&trace, argc-1, &argv[1]);
3131
3132 /* summary_only implies summary option, but don't overwrite summary if set */
3133 if (trace.summary_only)
3134 trace.summary = trace.summary_only;
3135
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003136 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3137 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003138 pr_err("Please specify something to trace.\n");
3139 return -1;
3140 }
3141
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003142 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003143 pr_err("The -e option can't be used with --no-syscalls.\n");
3144 goto out;
3145 }
3146
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003147 if (output_name != NULL) {
3148 err = trace__open_output(&trace, output_name);
3149 if (err < 0) {
3150 perror("failed to create output file");
3151 goto out;
3152 }
3153 }
3154
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003155 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3156
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003157 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003158 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003159 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003160 fprintf(trace.output, "%s", bf);
3161 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003162 }
3163
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003164 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003165 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003166 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003167 fprintf(trace.output, "%s", bf);
3168 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003169 }
3170
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003171 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003172 trace.opts.target.system_wide = true;
3173
David Ahern6810fc92013-08-28 22:29:52 -06003174 if (input_name)
3175 err = trace__replay(&trace);
3176 else
3177 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003178
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003179out_close:
3180 if (output_name != NULL)
3181 fclose(trace.output);
3182out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003183 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003184}