blob: 17d11deeb88d4100628259cef1e5500291bc9773 [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;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001664
1665 if (machine__resolve(trace->host, &al, sample) < 0 ||
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03001666 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, evsel->attr.sample_max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001667 return -1;
1668
1669 return 0;
1670}
1671
1672static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1673{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001674 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001675 const unsigned int print_opts = EVSEL__PRINT_SYM |
1676 EVSEL__PRINT_DSO |
1677 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001678
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001679 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001680}
1681
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001682static const char *errno_to_name(struct perf_evsel *evsel, int err)
1683{
1684 struct perf_env *env = perf_evsel__env(evsel);
1685 const char *arch_name = perf_env__arch(env);
1686
1687 return arch_syscalls__strerrno(arch_name, err);
1688}
1689
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001690static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001691 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001692 struct perf_sample *sample)
1693{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001694 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001695 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001696 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001697 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001698 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001699 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001700 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001701
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001702 if (sc == NULL)
1703 return -1;
1704
David Ahern8fb598e2013-09-28 13:13:00 -06001705 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001706 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001707 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001708 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001709
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001710 trace__fprintf_sample(trace, evsel, sample, thread);
1711
David Ahernbf2575c2013-10-08 21:26:53 -06001712 if (trace->summary)
1713 thread__update_stats(ttrace, id, sample);
1714
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001715 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001716
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001717 if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001718 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1719 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001720 ++trace->stats.vfs_getname;
1721 }
1722
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001723 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001724 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001725 if (trace__filter_duration(trace, duration))
1726 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001727 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001728 } else if (trace->duration_filter)
1729 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001730
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001731 if (sample->callchain) {
1732 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1733 if (callchain_ret == 0) {
1734 if (callchain_cursor.nr < trace->min_stack)
1735 goto out;
1736 callchain_ret = 1;
1737 }
1738 }
1739
David Ahernfd2eaba2013-11-12 09:31:15 -07001740 if (trace->summary_only)
1741 goto out;
1742
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001743 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001744
1745 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001746 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001747 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001748 fprintf(trace->output, " ... [");
1749 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1750 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001751 }
1752
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001753 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001754 if (ret < 0)
1755 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001756signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001757 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001758 } else if (ret < 0) {
1759errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001760 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001761 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001762 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001763
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001764 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001765 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001766 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001767 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001768 else if (ttrace->ret_scnprintf) {
1769 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001770 struct syscall_arg arg = {
1771 .val = ret,
1772 .thread = thread,
1773 .trace = trace,
1774 };
1775 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001776 ttrace->ret_scnprintf = NULL;
1777 fprintf(trace->output, ") = %s", bf);
1778 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001779 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001780 else if (sc->fmt->errpid) {
1781 struct thread *child = machine__find_thread(trace->host, ret, ret);
1782
1783 if (child != NULL) {
1784 fprintf(trace->output, ") = %ld", ret);
1785 if (child->comm_set)
1786 fprintf(trace->output, " (%s)", thread__comm_str(child));
1787 thread__put(child);
1788 }
1789 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001790 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001791
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001792 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001793
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001794 if (callchain_ret > 0)
1795 trace__fprintf_callchain(trace, sample);
1796 else if (callchain_ret < 0)
1797 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001798out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001799 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001800 err = 0;
1801out_put:
1802 thread__put(thread);
1803 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001804}
1805
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001806static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001807 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001808 struct perf_sample *sample)
1809{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001810 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1811 struct thread_trace *ttrace;
1812 size_t filename_len, entry_str_len, to_move;
1813 ssize_t remaining_space;
1814 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001815 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001816
1817 if (!thread)
1818 goto out;
1819
1820 ttrace = thread__priv(thread);
1821 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001822 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001823
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001824 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001825 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001826 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001827
1828 if (ttrace->filename.namelen < filename_len) {
1829 char *f = realloc(ttrace->filename.name, filename_len + 1);
1830
1831 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001832 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001833
1834 ttrace->filename.namelen = filename_len;
1835 ttrace->filename.name = f;
1836 }
1837
1838 strcpy(ttrace->filename.name, filename);
1839 ttrace->filename.pending_open = true;
1840
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001841 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001842 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001843
1844 entry_str_len = strlen(ttrace->entry_str);
1845 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1846 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001847 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001848
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001849 if (filename_len > (size_t)remaining_space) {
1850 filename += filename_len - remaining_space;
1851 filename_len = remaining_space;
1852 }
1853
1854 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1855 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1856 memmove(pos + filename_len, pos, to_move);
1857 memcpy(pos, filename, filename_len);
1858
1859 ttrace->filename.ptr = 0;
1860 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001861out_put:
1862 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001863out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001864 return 0;
1865}
1866
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001867static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001868 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001869 struct perf_sample *sample)
1870{
1871 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1872 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001873 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001874 sample->pid,
1875 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001876 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001877
1878 if (ttrace == NULL)
1879 goto out_dump;
1880
1881 ttrace->runtime_ms += runtime_ms;
1882 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001883out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001884 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001885 return 0;
1886
1887out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001888 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001889 evsel->name,
1890 perf_evsel__strval(evsel, sample, "comm"),
1891 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1892 runtime,
1893 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001894 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001895}
1896
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001897static int bpf_output__printer(enum binary_printer_ops op,
1898 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001899{
Wang Nan1d6c9402016-02-26 09:31:55 +00001900 unsigned char ch = (unsigned char)val;
1901
1902 switch (op) {
1903 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001904 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001905 case BINARY_PRINT_DATA_BEGIN:
1906 case BINARY_PRINT_LINE_BEGIN:
1907 case BINARY_PRINT_ADDR:
1908 case BINARY_PRINT_NUM_DATA:
1909 case BINARY_PRINT_NUM_PAD:
1910 case BINARY_PRINT_SEP:
1911 case BINARY_PRINT_CHAR_PAD:
1912 case BINARY_PRINT_LINE_END:
1913 case BINARY_PRINT_DATA_END:
1914 default:
1915 break;
1916 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001917
1918 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001919}
1920
1921static void bpf_output__fprintf(struct trace *trace,
1922 struct perf_sample *sample)
1923{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001924 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1925 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001926}
1927
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001928static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1929 union perf_event *event __maybe_unused,
1930 struct perf_sample *sample)
1931{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001932 int callchain_ret = 0;
1933
1934 if (sample->callchain) {
1935 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1936 if (callchain_ret == 0) {
1937 if (callchain_cursor.nr < trace->min_stack)
1938 goto out;
1939 callchain_ret = 1;
1940 }
1941 }
1942
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001943 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001944 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08001945
1946 if (trace->trace_syscalls)
1947 fprintf(trace->output, "( ): ");
1948
1949 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001950
Wang Nan1d6c9402016-02-26 09:31:55 +00001951 if (perf_evsel__is_bpf_output(evsel)) {
1952 bpf_output__fprintf(trace, sample);
1953 } else if (evsel->tp_format) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001954 event_format__fprintf(evsel->tp_format, sample->cpu,
1955 sample->raw_data, sample->raw_size,
1956 trace->output);
1957 }
1958
1959 fprintf(trace->output, ")\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001960
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03001961 if (callchain_ret > 0)
1962 trace__fprintf_callchain(trace, sample);
1963 else if (callchain_ret < 0)
1964 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
1965out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001966 return 0;
1967}
1968
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001969static void print_location(FILE *f, struct perf_sample *sample,
1970 struct addr_location *al,
1971 bool print_dso, bool print_sym)
1972{
1973
Namhyung Kimbb963e12017-02-17 17:17:38 +09001974 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001975 fprintf(f, "%s@", al->map->dso->long_name);
1976
Namhyung Kimbb963e12017-02-17 17:17:38 +09001977 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001978 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001979 al->addr - al->sym->start);
1980 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001981 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001982 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03001983 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001984}
1985
1986static int trace__pgfault(struct trace *trace,
1987 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03001988 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001989 struct perf_sample *sample)
1990{
1991 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001992 struct addr_location al;
1993 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04001994 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001995 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001996 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04001997
1998 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03001999
2000 if (sample->callchain) {
2001 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2002 if (callchain_ret == 0) {
2003 if (callchain_cursor.nr < trace->min_stack)
2004 goto out_put;
2005 callchain_ret = 1;
2006 }
2007 }
2008
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002009 ttrace = thread__trace(thread, trace->output);
2010 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002011 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002012
2013 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2014 ttrace->pfmaj++;
2015 else
2016 ttrace->pfmin++;
2017
2018 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002019 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002020
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002021 thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002022 sample->ip, &al);
2023
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002024 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002025
2026 fprintf(trace->output, "%sfault [",
2027 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2028 "maj" : "min");
2029
2030 print_location(trace->output, sample, &al, false, true);
2031
2032 fprintf(trace->output, "] => ");
2033
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002034 thread__find_addr_location(thread, sample->cpumode, MAP__VARIABLE,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002035 sample->addr, &al);
2036
2037 if (!al.map) {
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002038 thread__find_addr_location(thread, sample->cpumode,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002039 MAP__FUNCTION, sample->addr, &al);
2040
2041 if (al.map)
2042 map_type = 'x';
2043 else
2044 map_type = '?';
2045 }
2046
2047 print_location(trace->output, sample, &al, true, false);
2048
2049 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002050
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002051 if (callchain_ret > 0)
2052 trace__fprintf_callchain(trace, sample);
2053 else if (callchain_ret < 0)
2054 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002055out:
2056 err = 0;
2057out_put:
2058 thread__put(thread);
2059 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002060}
2061
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002062static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002063 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002064 struct perf_sample *sample)
2065{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002066 /*
2067 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2068 * and don't use sample->time unconditionally, we may end up having
2069 * some other event in the future without PERF_SAMPLE_TIME for good
2070 * reason, i.e. we may not be interested in its timestamps, just in
2071 * it taking place, picking some piece of information when it
2072 * appears in our event stream (vfs_getname comes to mind).
2073 */
2074 if (trace->base_time == 0 && !trace->full_time &&
2075 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002076 trace->base_time = sample->time;
2077}
2078
David Ahern6810fc92013-08-28 22:29:52 -06002079static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002080 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002081 struct perf_sample *sample,
2082 struct perf_evsel *evsel,
2083 struct machine *machine __maybe_unused)
2084{
2085 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002086 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002087 int err = 0;
2088
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002089 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002090
David Ahernaa07df62016-11-25 09:29:52 -07002091 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2092 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002093 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002094
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002095 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002096
David Ahern31605652013-12-04 19:41:41 -07002097 if (handler) {
2098 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002099 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002100 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002101out:
2102 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002103 return err;
2104}
2105
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002106static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002107{
2108 unsigned int rec_argc, i, j;
2109 const char **rec_argv;
2110 const char * const record_args[] = {
2111 "record",
2112 "-R",
2113 "-m", "1024",
2114 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002115 };
2116
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002117 const char * const sc_args[] = { "-e", };
2118 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2119 const char * const majpf_args[] = { "-e", "major-faults" };
2120 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2121 const char * const minpf_args[] = { "-e", "minor-faults" };
2122 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2123
David Ahern9aca7f12013-12-04 19:41:39 -07002124 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002125 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2126 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002127 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2128
2129 if (rec_argv == NULL)
2130 return -ENOMEM;
2131
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002132 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002133 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002134 rec_argv[j++] = record_args[i];
2135
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002136 if (trace->trace_syscalls) {
2137 for (i = 0; i < sc_args_nr; i++)
2138 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002139
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002140 /* event string may be different for older kernels - e.g., RHEL6 */
2141 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2142 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2143 else if (is_valid_tracepoint("syscalls:sys_enter"))
2144 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2145 else {
2146 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002147 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002148 return -1;
2149 }
David Ahern9aca7f12013-12-04 19:41:39 -07002150 }
David Ahern9aca7f12013-12-04 19:41:39 -07002151
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002152 if (trace->trace_pgfaults & TRACE_PFMAJ)
2153 for (i = 0; i < majpf_args_nr; i++)
2154 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002155
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002156 if (trace->trace_pgfaults & TRACE_PFMIN)
2157 for (i = 0; i < minpf_args_nr; i++)
2158 rec_argv[j++] = minpf_args[i];
2159
2160 for (i = 0; i < (unsigned int)argc; i++)
2161 rec_argv[j++] = argv[i];
2162
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002163 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002164}
2165
David Ahernbf2575c2013-10-08 21:26:53 -06002166static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2167
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002168static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002169{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002170 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002171
2172 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002173 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002174
2175 if (perf_evsel__field(evsel, "pathname") == NULL) {
2176 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002177 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002178 }
2179
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002180 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002181 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002182 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002183}
2184
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002185static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002186{
2187 struct perf_evsel *evsel;
2188 struct perf_event_attr attr = {
2189 .type = PERF_TYPE_SOFTWARE,
2190 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002191 };
2192
2193 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002194 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002195
2196 event_attr_init(&attr);
2197
2198 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002199 if (evsel)
2200 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002201
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002202 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002203}
2204
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002205static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2206{
2207 const u32 type = event->header.type;
2208 struct perf_evsel *evsel;
2209
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002210 if (type != PERF_RECORD_SAMPLE) {
2211 trace__process_event(trace, trace->host, event, sample);
2212 return;
2213 }
2214
2215 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2216 if (evsel == NULL) {
2217 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2218 return;
2219 }
2220
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002221 trace__set_base_time(trace, evsel, sample);
2222
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002223 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2224 sample->raw_data == NULL) {
2225 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2226 perf_evsel__name(evsel), sample->tid,
2227 sample->cpu, sample->raw_size);
2228 } else {
2229 tracepoint_handler handler = evsel->handler;
2230 handler(trace, evsel, event, sample);
2231 }
2232}
2233
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002234static int trace__add_syscall_newtp(struct trace *trace)
2235{
2236 int ret = -1;
2237 struct perf_evlist *evlist = trace->evlist;
2238 struct perf_evsel *sys_enter, *sys_exit;
2239
2240 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2241 if (sys_enter == NULL)
2242 goto out;
2243
2244 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2245 goto out_delete_sys_enter;
2246
2247 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2248 if (sys_exit == NULL)
2249 goto out_delete_sys_enter;
2250
2251 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2252 goto out_delete_sys_exit;
2253
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002254 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2255 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2256
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002257 perf_evlist__add(evlist, sys_enter);
2258 perf_evlist__add(evlist, sys_exit);
2259
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002260 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002261 /*
2262 * We're interested only in the user space callchain
2263 * leading to the syscall, allow overriding that for
2264 * debugging reasons using --kernel_syscall_callchains
2265 */
2266 sys_exit->attr.exclude_callchain_kernel = 1;
2267 }
2268
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002269 trace->syscalls.events.sys_enter = sys_enter;
2270 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002271
2272 ret = 0;
2273out:
2274 return ret;
2275
2276out_delete_sys_exit:
2277 perf_evsel__delete_priv(sys_exit);
2278out_delete_sys_enter:
2279 perf_evsel__delete_priv(sys_enter);
2280 goto out;
2281}
2282
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002283static int trace__set_ev_qualifier_filter(struct trace *trace)
2284{
2285 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002286 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002287 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2288 trace->ev_qualifier_ids.nr,
2289 trace->ev_qualifier_ids.entries);
2290
2291 if (filter == NULL)
2292 goto out_enomem;
2293
Mathieu Poirier3541c032016-09-16 08:44:04 -06002294 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2295 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002296 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002297 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002298 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002299
2300 free(filter);
2301out:
2302 return err;
2303out_enomem:
2304 errno = ENOMEM;
2305 goto out;
2306}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002307
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002308static int trace__set_filter_loop_pids(struct trace *trace)
2309{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002310 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002311 pid_t pids[32] = {
2312 getpid(),
2313 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002314 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2315
2316 while (thread && nr < ARRAY_SIZE(pids)) {
2317 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2318
2319 if (parent == NULL)
2320 break;
2321
2322 if (!strcmp(thread__comm_str(parent), "sshd")) {
2323 pids[nr++] = parent->tid;
2324 break;
2325 }
2326 thread = parent;
2327 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002328
2329 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2330}
2331
Namhyung Kimf15eb532012-10-05 14:02:16 +09002332static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002333{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002334 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002335 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002336 int err = -1, i;
2337 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002338 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002339 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002340
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002341 trace->live = true;
2342
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002343 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002344 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002345
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002346 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002347 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002348
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002349 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2350 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2351 if (pgfault_maj == NULL)
2352 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002353 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002354 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002355 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002356
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002357 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2358 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2359 if (pgfault_min == NULL)
2360 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002361 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002362 perf_evlist__add(evlist, pgfault_min);
2363 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002364
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002365 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002366 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2367 trace__sched_stat_runtime))
2368 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002369
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002370 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2371 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002372 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002373 goto out_delete_evlist;
2374 }
2375
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002376 err = trace__symbols_init(trace, evlist);
2377 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002378 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002379 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002380 }
2381
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002382 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002383
Namhyung Kimf15eb532012-10-05 14:02:16 +09002384 signal(SIGCHLD, sig_handler);
2385 signal(SIGINT, sig_handler);
2386
2387 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002388 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002389 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002390 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002391 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002392 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002393 }
2394 }
2395
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002396 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002397 if (err < 0)
2398 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002399
Wang Nanba504232016-02-26 09:31:54 +00002400 err = bpf__apply_obj_config();
2401 if (err) {
2402 char errbuf[BUFSIZ];
2403
2404 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2405 pr_err("ERROR: Apply config to BPF failed: %s\n",
2406 errbuf);
2407 goto out_error_open;
2408 }
2409
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002410 /*
2411 * Better not use !target__has_task() here because we need to cover the
2412 * case where no threads were specified in the command line, but a
2413 * workload was, and in that case we will fill in the thread_map when
2414 * we fork the workload in perf_evlist__prepare_workload.
2415 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002416 if (trace->filter_pids.nr > 0)
2417 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002418 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002419 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002420
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002421 if (err < 0)
2422 goto out_error_mem;
2423
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002424 if (trace->ev_qualifier_ids.nr > 0) {
2425 err = trace__set_ev_qualifier_filter(trace);
2426 if (err < 0)
2427 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002428
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002429 pr_debug("event qualifier tracepoint filter: %s\n",
2430 trace->syscalls.events.sys_exit->filter);
2431 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002432
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002433 err = perf_evlist__apply_filters(evlist, &evsel);
2434 if (err < 0)
2435 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002436
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002437 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002438 if (err < 0)
2439 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002440
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002441 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002442 perf_evlist__enable(evlist);
2443
Namhyung Kimf15eb532012-10-05 14:02:16 +09002444 if (forks)
2445 perf_evlist__start_workload(evlist);
2446
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002447 if (trace->opts.initial_delay) {
2448 usleep(trace->opts.initial_delay * 1000);
2449 perf_evlist__enable(evlist);
2450 }
2451
Jiri Olsae13798c2015-06-23 00:36:02 +02002452 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002453 evlist->threads->nr > 1 ||
2454 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002455
2456 /*
2457 * Now that we already used evsel->attr to ask the kernel to setup the
2458 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2459 * trace__resolve_callchain(), allowing per-event max-stack settings
2460 * to override an explicitely set --max-stack global setting.
2461 */
2462 evlist__for_each_entry(evlist, evsel) {
2463 if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) &&
2464 evsel->attr.sample_max_stack == 0)
2465 evsel->attr.sample_max_stack = trace->max_stack;
2466 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002467again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002468 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002469
2470 for (i = 0; i < evlist->nr_mmaps; i++) {
2471 union perf_event *event;
2472
2473 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002474 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002475
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002476 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002477
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002478 err = perf_evlist__parse_sample(evlist, event, &sample);
2479 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002480 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002481 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002482 }
2483
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002484 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002485next_event:
2486 perf_evlist__mmap_consume(evlist, i);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002487
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002488 if (interrupted)
2489 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002490
2491 if (done && !draining) {
2492 perf_evlist__disable(evlist);
2493 draining = true;
2494 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002495 }
2496 }
2497
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002498 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002499 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002500
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002501 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2502 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2503 draining = true;
2504
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002505 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002506 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002507 } else {
2508 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002509 }
2510
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002511out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002512 thread__zput(trace->current);
2513
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002514 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002515
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002516 if (!err) {
2517 if (trace->summary)
2518 trace__fprintf_thread_summary(trace, trace->output);
2519
2520 if (trace->show_tool_stats) {
2521 fprintf(trace->output, "Stats:\n "
2522 " vfs_getname : %" PRIu64 "\n"
2523 " proc_getname: %" PRIu64 "\n",
2524 trace->stats.vfs_getname,
2525 trace->stats.proc_getname);
2526 }
2527 }
David Ahernbf2575c2013-10-08 21:26:53 -06002528
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002529out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002530 trace__symbols__exit(trace);
2531
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002532 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002533 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002534 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002535 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002536{
2537 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002538
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002539out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002540 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002541 goto out_error;
2542
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002543out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002544 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002545 goto out_error;
2546
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002547out_error_mmap:
2548 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2549 goto out_error;
2550
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002551out_error_open:
2552 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2553
2554out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002555 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302556 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002557
2558out_error_apply_filters:
2559 fprintf(trace->output,
2560 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2561 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002562 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002563 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002564}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002565out_error_mem:
2566 fprintf(trace->output, "Not enough memory to run!\n");
2567 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002568
2569out_errno:
2570 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2571 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002572}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002573
David Ahern6810fc92013-08-28 22:29:52 -06002574static int trace__replay(struct trace *trace)
2575{
2576 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002577 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002578 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002579 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002580 .file = {
2581 .path = input_name,
2582 },
2583 .mode = PERF_DATA_MODE_READ,
2584 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002585 };
David Ahern6810fc92013-08-28 22:29:52 -06002586 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002587 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002588 int err = -1;
2589
2590 trace->tool.sample = trace__process_sample;
2591 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002592 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002593 trace->tool.comm = perf_event__process_comm;
2594 trace->tool.exit = perf_event__process_exit;
2595 trace->tool.fork = perf_event__process_fork;
2596 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302597 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002598 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302599 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002600
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002601 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002602 trace->tool.ordering_requires_timestamps = true;
2603
2604 /* add tid to output */
2605 trace->multiple_threads = true;
2606
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002607 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002608 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002609 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002610
David Ahernaa07df62016-11-25 09:29:52 -07002611 if (trace->opts.target.pid)
2612 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2613
2614 if (trace->opts.target.tid)
2615 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2616
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002617 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002618 goto out;
2619
David Ahern8fb598e2013-09-28 13:13:00 -06002620 trace->host = &session->machines.host;
2621
David Ahern6810fc92013-08-28 22:29:52 -06002622 err = perf_session__set_tracepoints_handlers(session, handlers);
2623 if (err)
2624 goto out;
2625
Namhyung Kim003824e2013-11-12 15:25:00 +09002626 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2627 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002628 /* older kernels have syscalls tp versus raw_syscalls */
2629 if (evsel == NULL)
2630 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2631 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002632
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002633 if (evsel &&
2634 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2635 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002636 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2637 goto out;
2638 }
2639
2640 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2641 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002642 if (evsel == NULL)
2643 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2644 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002645 if (evsel &&
2646 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2647 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002648 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002649 goto out;
2650 }
2651
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002652 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002653 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2654 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2655 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2656 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2657 evsel->handler = trace__pgfault;
2658 }
2659
David Ahern6810fc92013-08-28 22:29:52 -06002660 setup_pager();
2661
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002662 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002663 if (err)
2664 pr_err("Failed to process events, error %d", err);
2665
David Ahernbf2575c2013-10-08 21:26:53 -06002666 else if (trace->summary)
2667 trace__fprintf_thread_summary(trace, trace->output);
2668
David Ahern6810fc92013-08-28 22:29:52 -06002669out:
2670 perf_session__delete(session);
2671
2672 return err;
2673}
2674
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002675static size_t trace__fprintf_threads_header(FILE *fp)
2676{
2677 size_t printed;
2678
Pekka Enberg99ff7152013-11-12 16:42:14 +02002679 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002680
2681 return printed;
2682}
2683
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002684DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2685 struct stats *stats;
2686 double msecs;
2687 int syscall;
2688)
2689{
2690 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2691 struct stats *stats = source->priv;
2692
2693 entry->syscall = source->i;
2694 entry->stats = stats;
2695 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2696}
2697
David Ahernbf2575c2013-10-08 21:26:53 -06002698static size_t thread__dump_stats(struct thread_trace *ttrace,
2699 struct trace *trace, FILE *fp)
2700{
David Ahernbf2575c2013-10-08 21:26:53 -06002701 size_t printed = 0;
2702 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002703 struct rb_node *nd;
2704 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002705
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002706 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002707 return 0;
2708
2709 printed += fprintf(fp, "\n");
2710
Milian Wolff834fd462015-08-06 11:24:29 +02002711 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2712 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2713 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002714
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002715 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002716 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002717 if (stats) {
2718 double min = (double)(stats->min) / NSEC_PER_MSEC;
2719 double max = (double)(stats->max) / NSEC_PER_MSEC;
2720 double avg = avg_stats(stats);
2721 double pct;
2722 u64 n = (u64) stats->n;
2723
2724 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2725 avg /= NSEC_PER_MSEC;
2726
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002727 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002728 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002729 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002730 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002731 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002732 }
David Ahernbf2575c2013-10-08 21:26:53 -06002733 }
2734
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002735 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002736 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002737
2738 return printed;
2739}
2740
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002741static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002742{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002743 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002744 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002745 double ratio;
2746
2747 if (ttrace == NULL)
2748 return 0;
2749
2750 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2751
Pekka Enberg15e65c62013-11-14 18:43:30 +02002752 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002753 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002754 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002755 if (ttrace->pfmaj)
2756 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2757 if (ttrace->pfmin)
2758 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002759 if (trace->sched)
2760 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2761 else if (fputc('\n', fp) != EOF)
2762 ++printed;
2763
David Ahernbf2575c2013-10-08 21:26:53 -06002764 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002765
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002766 return printed;
2767}
David Ahern896cbb52013-09-28 13:12:59 -06002768
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002769static unsigned long thread__nr_events(struct thread_trace *ttrace)
2770{
2771 return ttrace ? ttrace->nr_events : 0;
2772}
2773
2774DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2775 struct thread *thread;
2776)
2777{
2778 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002779}
2780
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002781static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2782{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002783 size_t printed = trace__fprintf_threads_header(fp);
2784 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002785 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002786
Kan Liang91e467b2017-09-10 19:23:14 -07002787 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2788 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2789
2790 if (threads == NULL) {
2791 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2792 return 0;
2793 }
2794
2795 resort_rb__for_each_entry(nd, threads)
2796 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2797
2798 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002799 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002800 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002801}
2802
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002803static int trace__set_duration(const struct option *opt, const char *str,
2804 int unset __maybe_unused)
2805{
2806 struct trace *trace = opt->value;
2807
2808 trace->duration_filter = atof(str);
2809 return 0;
2810}
2811
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002812static int trace__set_filter_pids(const struct option *opt, const char *str,
2813 int unset __maybe_unused)
2814{
2815 int ret = -1;
2816 size_t i;
2817 struct trace *trace = opt->value;
2818 /*
2819 * FIXME: introduce a intarray class, plain parse csv and create a
2820 * { int nr, int entries[] } struct...
2821 */
2822 struct intlist *list = intlist__new(str);
2823
2824 if (list == NULL)
2825 return -1;
2826
2827 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2828 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2829
2830 if (trace->filter_pids.entries == NULL)
2831 goto out;
2832
2833 trace->filter_pids.entries[0] = getpid();
2834
2835 for (i = 1; i < trace->filter_pids.nr; ++i)
2836 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2837
2838 intlist__delete(list);
2839 ret = 0;
2840out:
2841 return ret;
2842}
2843
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002844static int trace__open_output(struct trace *trace, const char *filename)
2845{
2846 struct stat st;
2847
2848 if (!stat(filename, &st) && st.st_size) {
2849 char oldname[PATH_MAX];
2850
2851 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2852 unlink(oldname);
2853 rename(filename, oldname);
2854 }
2855
2856 trace->output = fopen(filename, "w");
2857
2858 return trace->output == NULL ? -errno : 0;
2859}
2860
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002861static int parse_pagefaults(const struct option *opt, const char *str,
2862 int unset __maybe_unused)
2863{
2864 int *trace_pgfaults = opt->value;
2865
2866 if (strcmp(str, "all") == 0)
2867 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2868 else if (strcmp(str, "maj") == 0)
2869 *trace_pgfaults |= TRACE_PFMAJ;
2870 else if (strcmp(str, "min") == 0)
2871 *trace_pgfaults |= TRACE_PFMIN;
2872 else
2873 return -1;
2874
2875 return 0;
2876}
2877
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002878static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2879{
2880 struct perf_evsel *evsel;
2881
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002882 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002883 evsel->handler = handler;
2884}
2885
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002886/*
2887 * XXX: Hackish, just splitting the combined -e+--event (syscalls
2888 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
2889 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
2890 *
2891 * It'd be better to introduce a parse_options() variant that would return a
2892 * list with the terms it didn't match to an event...
2893 */
2894static int trace__parse_events_option(const struct option *opt, const char *str,
2895 int unset __maybe_unused)
2896{
2897 struct trace *trace = (struct trace *)opt->value;
2898 const char *s = str;
2899 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002900 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002901 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
2902 char group_name[PATH_MAX];
2903
2904 if (strace_groups_dir == NULL)
2905 return -1;
2906
2907 if (*s == '!') {
2908 ++s;
2909 trace->not_ev_qualifier = true;
2910 }
2911
2912 while (1) {
2913 if ((sep = strchr(s, ',')) != NULL)
2914 *sep = '\0';
2915
2916 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03002917 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
2918 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03002919 list = 1;
2920 } else {
2921 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
2922 if (access(group_name, R_OK) == 0)
2923 list = 1;
2924 }
2925
2926 if (lists[list]) {
2927 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
2928 } else {
2929 lists[list] = malloc(len);
2930 if (lists[list] == NULL)
2931 goto out;
2932 strcpy(lists[list], s);
2933 }
2934
2935 if (!sep)
2936 break;
2937
2938 *sep = ',';
2939 s = sep + 1;
2940 }
2941
2942 if (lists[1] != NULL) {
2943 struct strlist_config slist_config = {
2944 .dirname = strace_groups_dir,
2945 };
2946
2947 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
2948 if (trace->ev_qualifier == NULL) {
2949 fputs("Not enough memory to parse event qualifier", trace->output);
2950 goto out;
2951 }
2952
2953 if (trace__validate_ev_qualifier(trace))
2954 goto out;
2955 }
2956
2957 err = 0;
2958
2959 if (lists[0]) {
2960 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
2961 "event selector. use 'perf list' to list available events",
2962 parse_events_option);
2963 err = parse_events_option(&o, lists[0], 0);
2964 }
2965out:
2966 if (sep)
2967 *sep = ',';
2968
2969 return err;
2970}
2971
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002972int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002973{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08002974 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09002975 "perf trace [<options>] [<command>]",
2976 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06002977 "perf trace record [<options>] [<command>]",
2978 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002979 NULL
2980 };
2981 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002982 .syscalls = {
2983 . max = -1,
2984 },
2985 .opts = {
2986 .target = {
2987 .uid = UINT_MAX,
2988 .uses_mmap = true,
2989 },
2990 .user_freq = UINT_MAX,
2991 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03002992 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03002993 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04002994 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002995 },
Milian Wolff007d66a2015-08-05 16:52:23 -03002996 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03002997 .show_comm = true,
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002998 .trace_syscalls = true,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002999 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003000 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003001 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003002 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003003 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003004 OPT_CALLBACK('e', "event", &trace, "event",
3005 "event/syscall selector. use 'perf list' to list available events",
3006 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003007 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3008 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003009 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003010 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3011 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003012 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003013 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003014 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3015 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003016 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003017 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003018 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3019 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003020 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003021 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003022 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003023 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003024 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003025 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003026 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3027 "number of mmap data pages",
3028 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003029 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003030 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003031 OPT_CALLBACK(0, "duration", &trace, "float",
3032 "show only events with duration > N.M ms",
3033 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003034 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003035 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003036 OPT_BOOLEAN('T', "time", &trace.full_time,
3037 "Show full timestamp, not time relative to first start"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003038 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3039 "Show only syscall summary with statistics"),
3040 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3041 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003042 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3043 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003044 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003045 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003046 OPT_CALLBACK(0, "call-graph", &trace.opts,
3047 "record_mode[,record_size]", record_callchain_help,
3048 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003049 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3050 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003051 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3052 "Set the minimum stack depth when parsing the callchain, "
3053 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003054 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3055 "Set the maximum stack depth when parsing the callchain, "
3056 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003057 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003058 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3059 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003060 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3061 "per thread proc mmap processing timeout in ms"),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003062 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3063 "ms to wait before starting measurement after program "
3064 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003065 OPT_END()
3066 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003067 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003068 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003069 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003070 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003071 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003072
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003073 signal(SIGSEGV, sighandler_dump_stack);
3074 signal(SIGFPE, sighandler_dump_stack);
3075
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003076 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003077 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003078
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003079 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003080 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003081 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003082 goto out;
3083 }
3084
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003085 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3086 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003087
Wang Nand7888572016-04-08 15:07:24 +00003088 err = bpf__setup_stdout(trace.evlist);
3089 if (err) {
3090 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3091 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3092 goto out;
3093 }
3094
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003095 err = -1;
3096
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003097 if (trace.trace_pgfaults) {
3098 trace.opts.sample_address = true;
3099 trace.opts.sample_time = true;
3100 }
3101
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003102 if (trace.opts.mmap_pages == UINT_MAX)
3103 mmap_pages_user_set = false;
3104
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003105 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melofe176082016-05-19 11:34:06 -03003106 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl_perf_event_max_stack;
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003107 max_stack_user_set = false;
3108 }
3109
3110#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003111 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003112 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003113 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003114#endif
3115
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003116 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003117 if (!mmap_pages_user_set && geteuid() == 0)
3118 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3119
Milian Wolff566a0882016-04-08 13:34:15 +02003120 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003121 }
Milian Wolff566a0882016-04-08 13:34:15 +02003122
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003123 if (trace.evlist->nr_entries > 0)
3124 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3125
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003126 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3127 return trace__record(&trace, argc-1, &argv[1]);
3128
3129 /* summary_only implies summary option, but don't overwrite summary if set */
3130 if (trace.summary_only)
3131 trace.summary = trace.summary_only;
3132
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003133 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3134 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003135 pr_err("Please specify something to trace.\n");
3136 return -1;
3137 }
3138
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003139 if (!trace.trace_syscalls && trace.ev_qualifier) {
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003140 pr_err("The -e option can't be used with --no-syscalls.\n");
3141 goto out;
3142 }
3143
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003144 if (output_name != NULL) {
3145 err = trace__open_output(&trace, output_name);
3146 if (err < 0) {
3147 perror("failed to create output file");
3148 goto out;
3149 }
3150 }
3151
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003152 trace.open_id = syscalltbl__id(trace.sctbl, "open");
3153
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003154 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003155 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003156 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003157 fprintf(trace.output, "%s", bf);
3158 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003159 }
3160
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003161 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003162 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003163 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003164 fprintf(trace.output, "%s", bf);
3165 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003166 }
3167
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003168 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003169 trace.opts.target.system_wide = true;
3170
David Ahern6810fc92013-08-28 22:29:52 -06003171 if (input_name)
3172 err = trace__replay(&trace);
3173 else
3174 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003175
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003176out_close:
3177 if (output_name != NULL)
3178 fclose(trace.output);
3179out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003180 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003181}