blob: 43a699cfcadfd8a8044ff190aabd6c0af9c519e6 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -030022#include "util/cgroup.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030023#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030024#include "util/debug.h"
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +010025#include "util/env.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030026#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030027#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060028#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030029#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030030#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060031#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030032#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060033#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030034#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060035#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030036#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060037#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030038#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010039#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070040#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000041#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020042#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030043#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030044#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030045#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030046#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030047
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030048#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030049#include <inttypes.h>
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030050#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030051#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030052#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030053#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020054#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030055#include <linux/filter.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melobafae982018-01-22 16:42:16 -030060#include <fcntl.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030061
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030062#include "sane_ctype.h"
63
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030064#ifndef O_CLOEXEC
65# define O_CLOEXEC 02000000
66#endif
67
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030068#ifndef F_LINUX_SPECIFIC_BASE
69# define F_LINUX_SPECIFIC_BASE 1024
70#endif
71
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030072struct trace {
73 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030074 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030075 struct {
76 int max;
77 struct syscall *table;
78 struct {
79 struct perf_evsel *sys_enter,
80 *sys_exit;
81 } events;
82 } syscalls;
83 struct record_opts opts;
84 struct perf_evlist *evlist;
85 struct machine *host;
86 struct thread *current;
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -030087 struct cgroup *cgroup;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030088 u64 base_time;
89 FILE *output;
90 unsigned long nr_events;
91 struct strlist *ev_qualifier;
92 struct {
93 size_t nr;
94 int *entries;
95 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030096 struct {
97 size_t nr;
98 pid_t *entries;
99 } filter_pids;
100 double duration_filter;
101 double runtime_ms;
102 struct {
103 u64 vfs_getname,
104 proc_getname;
105 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300106 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300107 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300108 bool not_ev_qualifier;
109 bool live;
110 bool full_time;
111 bool sched;
112 bool multiple_threads;
113 bool summary;
114 bool summary_only;
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -0300115 bool failure_only;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300116 bool show_comm;
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -0300117 bool print_sample;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300118 bool show_tool_stats;
119 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300120 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121 bool force;
122 bool vfs_getname;
123 int trace_pgfaults;
124};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300125
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300126struct tp_field {
127 int offset;
128 union {
129 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
130 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
131 };
132};
133
134#define TP_UINT_FIELD(bits) \
135static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
136{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500137 u##bits value; \
138 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
139 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300140}
141
142TP_UINT_FIELD(8);
143TP_UINT_FIELD(16);
144TP_UINT_FIELD(32);
145TP_UINT_FIELD(64);
146
147#define TP_UINT_FIELD__SWAPPED(bits) \
148static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
149{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500150 u##bits value; \
151 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300152 return bswap_##bits(value);\
153}
154
155TP_UINT_FIELD__SWAPPED(16);
156TP_UINT_FIELD__SWAPPED(32);
157TP_UINT_FIELD__SWAPPED(64);
158
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300159static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300160{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300161 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300162
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300163 switch (size) {
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300164 case 1:
165 field->integer = tp_field__u8;
166 break;
167 case 2:
168 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
169 break;
170 case 4:
171 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
172 break;
173 case 8:
174 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
175 break;
176 default:
177 return -1;
178 }
179
180 return 0;
181}
182
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300183static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap)
184{
185 return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
186}
187
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300188static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
189{
190 return sample->raw_data + field->offset;
191}
192
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300193static int __tp_field__init_ptr(struct tp_field *field, int offset)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300194{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300195 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300196 field->pointer = tp_field__ptr;
197 return 0;
198}
199
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300200static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
201{
202 return __tp_field__init_ptr(field, format_field->offset);
203}
204
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300205struct syscall_tp {
206 struct tp_field id;
207 union {
208 struct tp_field args, ret;
209 };
210};
211
212static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
213 struct tp_field *field,
214 const char *name)
215{
216 struct format_field *format_field = perf_evsel__field(evsel, name);
217
218 if (format_field == NULL)
219 return -1;
220
221 return tp_field__init_uint(field, format_field, evsel->needs_swap);
222}
223
224#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
225 ({ struct syscall_tp *sc = evsel->priv;\
226 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
227
228static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
229 struct tp_field *field,
230 const char *name)
231{
232 struct format_field *format_field = perf_evsel__field(evsel, name);
233
234 if (format_field == NULL)
235 return -1;
236
237 return tp_field__init_ptr(field, format_field);
238}
239
240#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
241 ({ struct syscall_tp *sc = evsel->priv;\
242 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
243
244static void perf_evsel__delete_priv(struct perf_evsel *evsel)
245{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300246 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300247 perf_evsel__delete(evsel);
248}
249
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -0300250static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel)
251{
252 struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
253
254 if (evsel->priv != NULL) {
255 if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr"))
256 goto out_delete;
257 return 0;
258 }
259
260 return -ENOMEM;
261out_delete:
262 zfree(&evsel->priv);
263 return -ENOENT;
264}
265
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300266static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler)
Namhyung Kim96695d42013-11-12 08:51:45 -0300267{
268 evsel->priv = malloc(sizeof(struct syscall_tp));
269 if (evsel->priv != NULL) {
270 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
271 goto out_delete;
272
273 evsel->handler = handler;
274 return 0;
275 }
276
277 return -ENOMEM;
278
279out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300280 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300281 return -ENOENT;
282}
283
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300284static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300285{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300286 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300287
David Ahern9aca7f12013-12-04 19:41:39 -0700288 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200289 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700290 evsel = perf_evsel__newtp("syscalls", direction);
291
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200292 if (IS_ERR(evsel))
293 return NULL;
294
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300295 if (perf_evsel__init_raw_syscall_tp(evsel, handler))
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200296 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300297
298 return evsel;
299
300out_delete:
301 perf_evsel__delete_priv(evsel);
302 return NULL;
303}
304
305#define perf_evsel__sc_tp_uint(evsel, name, sample) \
306 ({ struct syscall_tp *fields = evsel->priv; \
307 fields->name.integer(&fields->name, sample); })
308
309#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
310 ({ struct syscall_tp *fields = evsel->priv; \
311 fields->name.pointer(&fields->name, sample); })
312
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300313size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
314{
315 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316
Arnaldo Carvalho de Melobc972ad2018-07-26 15:30:33 -0300317 if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL)
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300318 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300319
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300320 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300321}
322
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300323static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
324 const char *intfmt,
325 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300326{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300327 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300328}
329
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300330static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
331 struct syscall_arg *arg)
332{
333 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
334}
335
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300336#define SCA_STRARRAY syscall_arg__scnprintf_strarray
337
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300338struct strarrays {
339 int nr_entries;
340 struct strarray **entries;
341};
342
343#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
344 .nr_entries = ARRAY_SIZE(array), \
345 .entries = array, \
346}
347
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300348size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
349 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300350{
351 struct strarrays *sas = arg->parm;
352 int i;
353
354 for (i = 0; i < sas->nr_entries; ++i) {
355 struct strarray *sa = sas->entries[i];
356 int idx = arg->val - sa->offset;
357
358 if (idx >= 0 && idx < sa->nr_entries) {
359 if (sa->entries[idx] == NULL)
360 break;
361 return scnprintf(bf, size, "%s", sa->entries[idx]);
362 }
363 }
364
365 return scnprintf(bf, size, "%d", arg->val);
366}
367
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300368#ifndef AT_FDCWD
369#define AT_FDCWD -100
370#endif
371
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300372static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
373 struct syscall_arg *arg)
374{
375 int fd = arg->val;
376
377 if (fd == AT_FDCWD)
378 return scnprintf(bf, size, "CWD");
379
380 return syscall_arg__scnprintf_fd(bf, size, arg);
381}
382
383#define SCA_FDAT syscall_arg__scnprintf_fd_at
384
385static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
386 struct syscall_arg *arg);
387
388#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
389
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300390size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300391{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300392 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300393}
394
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300395size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300396{
397 return scnprintf(bf, size, "%d", arg->val);
398}
399
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300400size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
401{
402 return scnprintf(bf, size, "%ld", arg->val);
403}
404
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300405static const char *bpf_cmd[] = {
406 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
407 "MAP_GET_NEXT_KEY", "PROG_LOAD",
408};
409static DEFINE_STRARRAY(bpf_cmd);
410
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300411static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
412static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300413
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300414static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
415static DEFINE_STRARRAY(itimers);
416
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300417static const char *keyctl_options[] = {
418 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
419 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
420 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
421 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
422 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
423};
424static DEFINE_STRARRAY(keyctl_options);
425
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300426static const char *whences[] = { "SET", "CUR", "END",
427#ifdef SEEK_DATA
428"DATA",
429#endif
430#ifdef SEEK_HOLE
431"HOLE",
432#endif
433};
434static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300435
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300436static const char *fcntl_cmds[] = {
437 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300438 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
439 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
440 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300441};
442static DEFINE_STRARRAY(fcntl_cmds);
443
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300444static const char *fcntl_linux_specific_cmds[] = {
445 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
446 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300447 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300448};
449
450static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
451
452static struct strarray *fcntl_cmds_arrays[] = {
453 &strarray__fcntl_cmds,
454 &strarray__fcntl_linux_specific_cmds,
455};
456
457static DEFINE_STRARRAYS(fcntl_cmds_arrays);
458
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300459static const char *rlimit_resources[] = {
460 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
461 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
462 "RTTIME",
463};
464static DEFINE_STRARRAY(rlimit_resources);
465
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300466static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
467static DEFINE_STRARRAY(sighow);
468
David Ahern4f8c1b72013-09-22 19:45:00 -0600469static const char *clockid[] = {
470 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300471 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
472 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600473};
474static DEFINE_STRARRAY(clockid);
475
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300476static const char *socket_families[] = {
477 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
478 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
479 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
480 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
481 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
482 "ALG", "NFC", "VSOCK",
483};
484static DEFINE_STRARRAY(socket_families);
485
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300486static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
487 struct syscall_arg *arg)
488{
489 size_t printed = 0;
490 int mode = arg->val;
491
492 if (mode == F_OK) /* 0 */
493 return scnprintf(bf, size, "F");
494#define P_MODE(n) \
495 if (mode & n##_OK) { \
496 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
497 mode &= ~n##_OK; \
498 }
499
500 P_MODE(R);
501 P_MODE(W);
502 P_MODE(X);
503#undef P_MODE
504
505 if (mode)
506 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
507
508 return printed;
509}
510
511#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
512
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300513static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
514 struct syscall_arg *arg);
515
516#define SCA_FILENAME syscall_arg__scnprintf_filename
517
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300518static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
519 struct syscall_arg *arg)
520{
521 int printed = 0, flags = arg->val;
522
523#define P_FLAG(n) \
524 if (flags & O_##n) { \
525 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
526 flags &= ~O_##n; \
527 }
528
529 P_FLAG(CLOEXEC);
530 P_FLAG(NONBLOCK);
531#undef P_FLAG
532
533 if (flags)
534 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
535
536 return printed;
537}
538
539#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
540
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300541#ifndef GRND_NONBLOCK
542#define GRND_NONBLOCK 0x0001
543#endif
544#ifndef GRND_RANDOM
545#define GRND_RANDOM 0x0002
546#endif
547
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300548static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
549 struct syscall_arg *arg)
550{
551 int printed = 0, flags = arg->val;
552
553#define P_FLAG(n) \
554 if (flags & GRND_##n) { \
555 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
556 flags &= ~GRND_##n; \
557 }
558
559 P_FLAG(RANDOM);
560 P_FLAG(NONBLOCK);
561#undef P_FLAG
562
563 if (flags)
564 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
565
566 return printed;
567}
568
569#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
570
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300571#define STRARRAY(name, array) \
572 { .scnprintf = SCA_STRARRAY, \
573 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300574
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +0100575#include "trace/beauty/arch_errno_names.c"
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300576#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300577#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300578#include "trace/beauty/futex_val3.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300579#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300580#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300581#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300582#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300583#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300584#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300585#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300586#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300587#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300588#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300589#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300590
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300591struct syscall_arg_fmt {
592 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
593 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300594 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300595 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300596};
597
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300598static struct syscall_fmt {
599 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300600 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300601 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300602 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300603 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300604 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300605 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300606} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300607 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300608 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300609 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300610 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300611 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300612 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300613 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300614 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300615 { .name = "clone", .errpid = true, .nr_args = 5,
616 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
617 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
618 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
619 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
620 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300621 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300623 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300624 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300625 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300626 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300627 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300628 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300629 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300630 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300631 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300632 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300633 .parm = &strarrays__fcntl_cmds_arrays,
634 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300635 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300636 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300638 { .name = "fstat", .alias = "newfstat", },
639 { .name = "fstatat", .alias = "newfstatat", },
640 { .name = "futex",
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300641 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
642 [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300643 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300644 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300645 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300646 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300647 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300648 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300649 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300650 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300651 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300652 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo2d1073d2018-01-09 12:03:47 -0300654 { .name = "gettid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300655 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300656 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300657#if defined(__i386__) || defined(__x86_64__)
658/*
659 * FIXME: Make this available to all arches.
660 */
Arnaldo Carvalho de Melo1cc47f22017-07-31 13:20:14 -0300661 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300662 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300663#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300664 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300665#endif
Arnaldo Carvalho de Melo1de30382017-10-31 11:32:23 -0300666 { .name = "kcmp", .nr_args = 5,
667 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
668 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
669 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
670 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
671 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300672 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300673 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300676 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300677 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300678 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300679 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300680 { .name = "lstat", .alias = "newlstat", },
681 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
683 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300684 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300685 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300686 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300688 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300689 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300690 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300691 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300692 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200693/* The standard mmap maps to old_mmap on s390x */
694#if defined(__s390x__)
695 .alias = "old_mmap",
696#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300697 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
698 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
699 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300700 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300701 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
702 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300705 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300706 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
707 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
708 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300710 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300711 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300717 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300718 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300719 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300720 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
721 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300722 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300723 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
724 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300726 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
727 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
728 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300730 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300731 { .name = "pkey_alloc",
732 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
733 { .name = "pkey_free",
734 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
735 { .name = "pkey_mprotect",
736 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
737 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
738 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300739 { .name = "poll", .timeout = true, },
740 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300741 { .name = "prctl", .alias = "arch_prctl",
742 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
743 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
744 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300745 { .name = "pread", .alias = "pread64", },
746 { .name = "preadv", .alias = "pread", },
747 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300748 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "pwrite", .alias = "pwrite64", },
750 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300756 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300757 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300758 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300759 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300760 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300761 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300764 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300765 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300766 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300768 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300769 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300770 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300771 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
772 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300773 { .name = "select", .timeout = true, },
774 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300775 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300776 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300777 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300778 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300779 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300780 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300781 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300782 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300783 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300784 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300785 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300786 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300787 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
788 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300789 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300790 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300791 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
792 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300793 { .name = "stat", .alias = "newstat", },
794 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300795 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
796 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
797 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300798 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300799 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300800 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300801 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300802 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300803 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300804 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300805 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300806 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300807 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300808 { .name = "uname", .alias = "newuname", },
809 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300810 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300811 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300812 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300813 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300814 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300815 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300816 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817};
818
819static int syscall_fmt__cmp(const void *name, const void *fmtp)
820{
821 const struct syscall_fmt *fmt = fmtp;
822 return strcmp(name, fmt->name);
823}
824
825static struct syscall_fmt *syscall_fmt__find(const char *name)
826{
827 const int nmemb = ARRAY_SIZE(syscall_fmts);
828 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
829}
830
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300831/*
832 * is_exit: is this "exit" or "exit_group"?
833 * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
834 */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300835struct syscall {
836 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300837 int nr_args;
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300838 bool is_exit;
839 bool is_open;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300840 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300841 const char *name;
842 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300843 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300844};
845
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300846/*
847 * We need to have this 'calculated' boolean because in some cases we really
848 * don't know what is the duration of a syscall, for instance, when we start
849 * a session and some threads are waiting for a syscall to finish, say 'poll',
850 * in which case all we can do is to print "( ? ) for duration and for the
851 * start timestamp.
852 */
853static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200854{
855 double duration = (double)t / NSEC_PER_MSEC;
856 size_t printed = fprintf(fp, "(");
857
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300858 if (!calculated)
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -0300859 printed += fprintf(fp, " ");
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300860 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200861 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
862 else if (duration >= 0.01)
863 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
864 else
865 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300866 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200867}
868
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300869/**
870 * filename.ptr: The filename char pointer that will be vfs_getname'd
871 * filename.entry_str_pos: Where to insert the string translated from
872 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300873 * ret_scnprintf: syscall args may set this to a different syscall return
874 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300875 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876struct thread_trace {
877 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300878 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300879 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400880 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300881 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300882 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300883 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300884 struct {
885 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300886 short int entry_str_pos;
887 bool pending_open;
888 unsigned int namelen;
889 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300890 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300891 struct {
892 int max;
893 char **table;
894 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600895
896 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897};
898
899static struct thread_trace *thread_trace__new(void)
900{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300901 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
902
903 if (ttrace)
904 ttrace->paths.max = -1;
905
David Ahernbf2575c2013-10-08 21:26:53 -0600906 ttrace->syscall_stats = intlist__new(NULL);
907
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909}
910
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300911static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300913 struct thread_trace *ttrace;
914
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300915 if (thread == NULL)
916 goto fail;
917
Namhyung Kim89dceb22014-10-06 09:46:03 +0900918 if (thread__priv(thread) == NULL)
919 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300920
Namhyung Kim89dceb22014-10-06 09:46:03 +0900921 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300922 goto fail;
923
Namhyung Kim89dceb22014-10-06 09:46:03 +0900924 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300925 ++ttrace->nr_events;
926
927 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300928fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300929 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300930 "WARNING: not enough memory, dropping samples!\n");
931 return NULL;
932}
933
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300934
935void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300936 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300937{
938 struct thread_trace *ttrace = thread__priv(arg->thread);
939
940 ttrace->ret_scnprintf = ret_scnprintf;
941}
942
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400943#define TRACE_PFMAJ (1 << 0)
944#define TRACE_PFMIN (1 << 1)
945
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300946static const size_t trace__entry_str_size = 2048;
947
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300948static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300949{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900950 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300951
952 if (fd > ttrace->paths.max) {
953 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
954
955 if (npath == NULL)
956 return -1;
957
958 if (ttrace->paths.max != -1) {
959 memset(npath + ttrace->paths.max + 1, 0,
960 (fd - ttrace->paths.max) * sizeof(char *));
961 } else {
962 memset(npath, 0, (fd + 1) * sizeof(char *));
963 }
964
965 ttrace->paths.table = npath;
966 ttrace->paths.max = fd;
967 }
968
969 ttrace->paths.table[fd] = strdup(pathname);
970
971 return ttrace->paths.table[fd] != NULL ? 0 : -1;
972}
973
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300974static int thread__read_fd_path(struct thread *thread, int fd)
975{
976 char linkname[PATH_MAX], pathname[PATH_MAX];
977 struct stat st;
978 int ret;
979
980 if (thread->pid_ == thread->tid) {
981 scnprintf(linkname, sizeof(linkname),
982 "/proc/%d/fd/%d", thread->pid_, fd);
983 } else {
984 scnprintf(linkname, sizeof(linkname),
985 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
986 }
987
988 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
989 return -1;
990
991 ret = readlink(linkname, pathname, sizeof(pathname));
992
993 if (ret < 0 || ret > st.st_size)
994 return -1;
995
996 pathname[ret] = '\0';
997 return trace__set_fd_pathname(thread, fd, pathname);
998}
999
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001000static const char *thread__fd_path(struct thread *thread, int fd,
1001 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001002{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001003 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004
1005 if (ttrace == NULL)
1006 return NULL;
1007
1008 if (fd < 0)
1009 return NULL;
1010
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001011 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001012 if (!trace->live)
1013 return NULL;
1014 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001015 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001016 return NULL;
1017 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001018
1019 return ttrace->paths.table[fd];
1020}
1021
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001022size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001023{
1024 int fd = arg->val;
1025 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001026 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027
1028 if (path)
1029 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1030
1031 return printed;
1032}
1033
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -03001034size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1035{
1036 size_t printed = scnprintf(bf, size, "%d", fd);
1037 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1038
1039 if (thread) {
1040 const char *path = thread__fd_path(thread, fd, trace);
1041
1042 if (path)
1043 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1044
1045 thread__put(thread);
1046 }
1047
1048 return printed;
1049}
1050
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001051static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1052 struct syscall_arg *arg)
1053{
1054 int fd = arg->val;
1055 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001056 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001057
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001058 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1059 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001060
1061 return printed;
1062}
1063
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001064static void thread__set_filename_pos(struct thread *thread, const char *bf,
1065 unsigned long ptr)
1066{
1067 struct thread_trace *ttrace = thread__priv(thread);
1068
1069 ttrace->filename.ptr = ptr;
1070 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1071}
1072
1073static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1074 struct syscall_arg *arg)
1075{
1076 unsigned long ptr = arg->val;
1077
1078 if (!arg->trace->vfs_getname)
1079 return scnprintf(bf, size, "%#x", ptr);
1080
1081 thread__set_filename_pos(arg->thread, bf, ptr);
1082 return 0;
1083}
1084
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001085static bool trace__filter_duration(struct trace *trace, double t)
1086{
1087 return t < (trace->duration_filter * NSEC_PER_MSEC);
1088}
1089
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001090static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001091{
1092 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1093
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001094 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001095}
1096
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001097/*
1098 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1099 * using ttrace->entry_time for a thread that receives a sys_exit without
1100 * first having received a sys_enter ("poll" issued before tracing session
1101 * starts, lost sys_enter exit due to ring buffer overflow).
1102 */
1103static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1104{
1105 if (tstamp > 0)
1106 return __trace__fprintf_tstamp(trace, tstamp, fp);
1107
1108 return fprintf(fp, " ? ");
1109}
1110
Namhyung Kimf15eb532012-10-05 14:02:16 +09001111static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001112static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001113
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001114static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001115{
1116 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001117 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001118}
1119
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001121 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122{
1123 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001124 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001126 if (trace->multiple_threads) {
1127 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001128 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001129 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001130 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131
1132 return printed;
1133}
1134
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001135static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001136 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137{
1138 int ret = 0;
1139
1140 switch (event->header.type) {
1141 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001142 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001143 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001144 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001145 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001147 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 break;
1149 }
1150
1151 return ret;
1152}
1153
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001154static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001156 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157 struct machine *machine)
1158{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001159 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001160 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001161}
1162
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001163static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1164{
1165 struct machine *machine = vmachine;
1166
1167 if (machine->kptr_restrict_warned)
1168 return NULL;
1169
1170 if (symbol_conf.kptr_restrict) {
1171 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1172 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1173 "Kernel samples will not be resolved.\n");
1174 machine->kptr_restrict_warned = true;
1175 return NULL;
1176 }
1177
1178 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1179}
1180
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001181static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1182{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001183 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001184
1185 if (err)
1186 return err;
1187
David Ahern8fb598e2013-09-28 13:13:00 -06001188 trace->host = machine__new_host();
1189 if (trace->host == NULL)
1190 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001191
Andrei Vagincbd5c172017-11-07 16:22:46 -08001192 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1193 if (err < 0)
1194 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001195
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001196 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001197 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001198 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001199out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001200 if (err)
1201 symbol__exit();
1202
1203 return err;
1204}
1205
Andrei Vagin33974a42017-11-07 16:22:45 -08001206static void trace__symbols__exit(struct trace *trace)
1207{
1208 machine__exit(trace->host);
1209 trace->host = NULL;
1210
1211 symbol__exit();
1212}
1213
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001214static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1215{
1216 int idx;
1217
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001218 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1219 nr_args = sc->fmt->nr_args;
1220
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001221 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1222 if (sc->arg_fmt == NULL)
1223 return -1;
1224
1225 for (idx = 0; idx < nr_args; ++idx) {
1226 if (sc->fmt)
1227 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1228 }
1229
1230 sc->nr_args = nr_args;
1231 return 0;
1232}
1233
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001234static int syscall__set_arg_fmts(struct syscall *sc)
1235{
1236 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001237 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001238
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001239 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001240 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1241 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001242
1243 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001244 (strcmp(field->name, "filename") == 0 ||
1245 strcmp(field->name, "path") == 0 ||
1246 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001247 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001248 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001249 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001250 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001251 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001252 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001253 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001254 else if ((strcmp(field->type, "int") == 0 ||
1255 strcmp(field->type, "unsigned int") == 0 ||
1256 strcmp(field->type, "long") == 0) &&
1257 (len = strlen(field->name)) >= 2 &&
1258 strcmp(field->name + len - 2, "fd") == 0) {
1259 /*
1260 * /sys/kernel/tracing/events/syscalls/sys_enter*
1261 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1262 * 65 int
1263 * 23 unsigned int
1264 * 7 unsigned long
1265 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001266 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001267 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001268 }
1269
1270 return 0;
1271}
1272
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001273static int trace__read_syscall_info(struct trace *trace, int id)
1274{
1275 char tp_name[128];
1276 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001277 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001278
1279 if (name == NULL)
1280 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001281
1282 if (id > trace->syscalls.max) {
1283 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1284
1285 if (nsyscalls == NULL)
1286 return -1;
1287
1288 if (trace->syscalls.max != -1) {
1289 memset(nsyscalls + trace->syscalls.max + 1, 0,
1290 (id - trace->syscalls.max) * sizeof(*sc));
1291 } else {
1292 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1293 }
1294
1295 trace->syscalls.table = nsyscalls;
1296 trace->syscalls.max = id;
1297 }
1298
1299 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001300 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001301
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001302 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001303
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001304 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001305 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001306
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001307 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001308 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001309 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001310 }
1311
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001312 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1313 return -1;
1314
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001315 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001316 return -1;
1317
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001318 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001319 /*
1320 * We need to check and discard the first variable '__syscall_nr'
1321 * or 'nr' that mean the syscall number. It is needless here.
1322 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1323 */
1324 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001325 sc->args = sc->args->next;
1326 --sc->nr_args;
1327 }
1328
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001329 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001330 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001331
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001332 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001333}
1334
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001335static int trace__validate_ev_qualifier(struct trace *trace)
1336{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001337 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001338 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001339 struct str_node *pos;
1340
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001341 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1342 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1343 sizeof(trace->ev_qualifier_ids.entries[0]));
1344
1345 if (trace->ev_qualifier_ids.entries == NULL) {
1346 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1347 trace->output);
1348 err = -EINVAL;
1349 goto out;
1350 }
1351
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001352 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001353 i = 0;
1354
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001355 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001356 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001357 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001358
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001359 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001360 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1361 if (id >= 0)
1362 goto matches;
1363
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001364 if (err == 0) {
1365 fputs("Error:\tInvalid syscall ", trace->output);
1366 err = -EINVAL;
1367 } else {
1368 fputs(", ", trace->output);
1369 }
1370
1371 fputs(sc, trace->output);
1372 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001373matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001374 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001375 if (match_next == -1)
1376 continue;
1377
1378 while (1) {
1379 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1380 if (id < 0)
1381 break;
1382 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1383 void *entries;
1384
1385 nr_allocated += 8;
1386 entries = realloc(trace->ev_qualifier_ids.entries,
1387 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1388 if (entries == NULL) {
1389 err = -ENOMEM;
1390 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1391 goto out_free;
1392 }
1393 trace->ev_qualifier_ids.entries = entries;
1394 }
1395 trace->ev_qualifier_ids.nr++;
1396 trace->ev_qualifier_ids.entries[i++] = id;
1397 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001398 }
1399
1400 if (err < 0) {
1401 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1402 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001403out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001404 zfree(&trace->ev_qualifier_ids.entries);
1405 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001406 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001407out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001408 return err;
1409}
1410
David Ahern55d43bca2015-02-19 15:00:22 -05001411/*
1412 * args is to be interpreted as a series of longs but we need to handle
1413 * 8-byte unaligned accesses. args points to raw_data within the event
1414 * and raw_data is guaranteed to be 8-byte unaligned because it is
1415 * preceded by raw_size which is a u32. So we need to copy args to a temp
1416 * variable to read it. Most notably this avoids extended load instructions
1417 * on unaligned addresses
1418 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001419unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001420{
1421 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001422 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001423
1424 memcpy(&val, p, sizeof(val));
1425 return val;
1426}
1427
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001428static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1429 struct syscall_arg *arg)
1430{
1431 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1432 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1433
1434 return scnprintf(bf, size, "arg%d: ", arg->idx);
1435}
1436
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001437static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1438 struct syscall_arg *arg, unsigned long val)
1439{
1440 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1441 arg->val = val;
1442 if (sc->arg_fmt[arg->idx].parm)
1443 arg->parm = sc->arg_fmt[arg->idx].parm;
1444 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1445 }
1446 return scnprintf(bf, size, "%ld", val);
1447}
1448
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001449static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001450 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001451 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001452{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001453 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001454 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001455 u8 bit = 1;
1456 struct syscall_arg arg = {
1457 .args = args,
1458 .idx = 0,
1459 .mask = 0,
1460 .trace = trace,
1461 .thread = thread,
1462 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001463 struct thread_trace *ttrace = thread__priv(thread);
1464
1465 /*
1466 * Things like fcntl will set this in its 'cmd' formatter to pick the
1467 * right formatter for the return value (an fd? file flags?), which is
1468 * not needed for syscalls that always return a given type, say an fd.
1469 */
1470 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001471
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001472 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001473 struct format_field *field;
1474
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001475 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001476 field = field->next, ++arg.idx, bit <<= 1) {
1477 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001478 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001479
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001480 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001481
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001482 /*
1483 * Suppress this argument if its value is zero and
1484 * and we don't have a string associated in an
1485 * strarray for it.
1486 */
David Ahern55d43bca2015-02-19 15:00:22 -05001487 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001488 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001489 (sc->arg_fmt[arg.idx].show_zero ||
1490 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001491 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1492 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001493 continue;
1494
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001495 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001496 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001497 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001498 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001499 } else if (IS_ERR(sc->tp_format)) {
1500 /*
1501 * If we managed to read the tracepoint /format file, then we
1502 * may end up not having any args, like with gettid(), so only
1503 * print the raw args when we didn't manage to read it.
1504 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001505 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001506 if (arg.mask & bit)
1507 goto next_arg;
1508 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001509 if (printed)
1510 printed += scnprintf(bf + printed, size - printed, ", ");
1511 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001512 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1513next_arg:
1514 ++arg.idx;
1515 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001516 }
1517 }
1518
1519 return printed;
1520}
1521
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001522typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001523 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001524 struct perf_sample *sample);
1525
1526static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001527 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001528{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001529
1530 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001531
1532 /*
1533 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1534 * before that, leaving at a higher verbosity level till that is
1535 * explained. Reproduced with plain ftrace with:
1536 *
1537 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1538 * grep "NR -1 " /t/trace_pipe
1539 *
1540 * After generating some load on the machine.
1541 */
1542 if (verbose > 1) {
1543 static u64 n;
1544 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1545 id, perf_evsel__name(evsel), ++n);
1546 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001547 return NULL;
1548 }
1549
1550 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1551 trace__read_syscall_info(trace, id))
1552 goto out_cant_read;
1553
1554 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1555 goto out_cant_read;
1556
1557 return &trace->syscalls.table[id];
1558
1559out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001560 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001561 fprintf(trace->output, "Problems reading syscall %d", id);
1562 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1563 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1564 fputs(" information\n", trace->output);
1565 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001566 return NULL;
1567}
1568
David Ahernbf2575c2013-10-08 21:26:53 -06001569static void thread__update_stats(struct thread_trace *ttrace,
1570 int id, struct perf_sample *sample)
1571{
1572 struct int_node *inode;
1573 struct stats *stats;
1574 u64 duration = 0;
1575
1576 inode = intlist__findnew(ttrace->syscall_stats, id);
1577 if (inode == NULL)
1578 return;
1579
1580 stats = inode->priv;
1581 if (stats == NULL) {
1582 stats = malloc(sizeof(struct stats));
1583 if (stats == NULL)
1584 return;
1585 init_stats(stats);
1586 inode->priv = stats;
1587 }
1588
1589 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1590 duration = sample->time - ttrace->entry_time;
1591
1592 update_stats(stats, duration);
1593}
1594
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001595static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001596{
1597 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001598 size_t printed;
1599
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001600 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001601 return 0;
1602
1603 ttrace = thread__priv(trace->current);
1604
1605 if (!ttrace->entry_pending)
1606 return 0;
1607
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001608 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001609 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1610 ttrace->entry_pending = false;
1611
1612 return printed;
1613}
1614
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001615static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1616 struct perf_sample *sample, struct thread *thread)
1617{
1618 int printed = 0;
1619
1620 if (trace->print_sample) {
1621 double ts = (double)sample->time / NSEC_PER_MSEC;
1622
1623 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1624 perf_evsel__name(evsel), ts,
1625 thread__comm_str(thread),
1626 sample->pid, sample->tid, sample->cpu);
1627 }
1628
1629 return printed;
1630}
1631
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001632static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001633 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001634 struct perf_sample *sample)
1635{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001636 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001637 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001638 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001639 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001640 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001641 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001642 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001643
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001644 if (sc == NULL)
1645 return -1;
1646
David Ahern8fb598e2013-09-28 13:13:00 -06001647 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001648 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001649 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001650 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001651
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001652 trace__fprintf_sample(trace, evsel, sample, thread);
1653
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001654 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001655
1656 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001657 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001658 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001659 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001660 }
1661
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001662 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001663 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001664
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001665 ttrace->entry_time = sample->time;
1666 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001667 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001668
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001669 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001670 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001672 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001673 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001674 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001675 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001676 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001677 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001679 /* See trace__vfs_getname & trace__sys_exit */
1680 ttrace->filename.pending_open = false;
1681 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001682
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001683 if (trace->current != thread) {
1684 thread__put(trace->current);
1685 trace->current = thread__get(thread);
1686 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001687 err = 0;
1688out_put:
1689 thread__put(thread);
1690 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001691}
1692
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001693static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1694 struct perf_sample *sample)
1695{
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001696 struct thread_trace *ttrace;
1697 struct thread *thread;
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001698 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
1699 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001700 char msg[1024];
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001701 void *args;
1702
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001703 if (sc == NULL)
1704 return -1;
1705
1706 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1707 ttrace = thread__trace(thread, trace->output);
1708 /*
1709 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1710 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1711 */
1712 if (ttrace == NULL)
1713 goto out_put;
1714
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001715 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001716 syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread);
1717 fprintf(trace->output, "%s", msg);
1718 err = 0;
1719out_put:
1720 thread__put(thread);
1721 return err;
1722}
1723
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001724static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1725 struct perf_sample *sample,
1726 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001727{
1728 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301729 int max_stack = evsel->attr.sample_max_stack ?
1730 evsel->attr.sample_max_stack :
1731 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001732
1733 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301734 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001735 return -1;
1736
1737 return 0;
1738}
1739
1740static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1741{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001742 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001743 const unsigned int print_opts = EVSEL__PRINT_SYM |
1744 EVSEL__PRINT_DSO |
1745 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001746
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001747 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001748}
1749
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001750static const char *errno_to_name(struct perf_evsel *evsel, int err)
1751{
1752 struct perf_env *env = perf_evsel__env(evsel);
1753 const char *arch_name = perf_env__arch(env);
1754
1755 return arch_syscalls__strerrno(arch_name, err);
1756}
1757
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001758static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001759 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001760 struct perf_sample *sample)
1761{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001762 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001763 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001764 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001765 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001766 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001767 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001768 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001769
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001770 if (sc == NULL)
1771 return -1;
1772
David Ahern8fb598e2013-09-28 13:13:00 -06001773 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001774 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001775 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001776 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001777
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001778 trace__fprintf_sample(trace, evsel, sample, thread);
1779
David Ahernbf2575c2013-10-08 21:26:53 -06001780 if (trace->summary)
1781 thread__update_stats(ttrace, id, sample);
1782
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001783 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001784
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001785 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001786 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1787 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001788 ++trace->stats.vfs_getname;
1789 }
1790
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001791 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001792 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001793 if (trace__filter_duration(trace, duration))
1794 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001795 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001796 } else if (trace->duration_filter)
1797 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001798
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001799 if (sample->callchain) {
1800 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1801 if (callchain_ret == 0) {
1802 if (callchain_cursor.nr < trace->min_stack)
1803 goto out;
1804 callchain_ret = 1;
1805 }
1806 }
1807
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001808 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001809 goto out;
1810
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001811 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001812
1813 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001814 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001815 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001816 fprintf(trace->output, " ... [");
1817 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1818 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001819 }
1820
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001821 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001822 if (ret < 0)
1823 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001824signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001825 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001826 } else if (ret < 0) {
1827errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001828 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001829 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001830 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001831
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001832 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001833 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001834 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001835 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001836 else if (ttrace->ret_scnprintf) {
1837 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001838 struct syscall_arg arg = {
1839 .val = ret,
1840 .thread = thread,
1841 .trace = trace,
1842 };
1843 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001844 ttrace->ret_scnprintf = NULL;
1845 fprintf(trace->output, ") = %s", bf);
1846 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001847 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001848 else if (sc->fmt->errpid) {
1849 struct thread *child = machine__find_thread(trace->host, ret, ret);
1850
1851 if (child != NULL) {
1852 fprintf(trace->output, ") = %ld", ret);
1853 if (child->comm_set)
1854 fprintf(trace->output, " (%s)", thread__comm_str(child));
1855 thread__put(child);
1856 }
1857 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001858 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001859
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001860 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001861
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001862 if (callchain_ret > 0)
1863 trace__fprintf_callchain(trace, sample);
1864 else if (callchain_ret < 0)
1865 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001866out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001867 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001868 err = 0;
1869out_put:
1870 thread__put(thread);
1871 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001872}
1873
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001874static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001875 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001876 struct perf_sample *sample)
1877{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001878 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1879 struct thread_trace *ttrace;
1880 size_t filename_len, entry_str_len, to_move;
1881 ssize_t remaining_space;
1882 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001883 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001884
1885 if (!thread)
1886 goto out;
1887
1888 ttrace = thread__priv(thread);
1889 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001890 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001891
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001892 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001893 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001894 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001895
1896 if (ttrace->filename.namelen < filename_len) {
1897 char *f = realloc(ttrace->filename.name, filename_len + 1);
1898
1899 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001900 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001901
1902 ttrace->filename.namelen = filename_len;
1903 ttrace->filename.name = f;
1904 }
1905
1906 strcpy(ttrace->filename.name, filename);
1907 ttrace->filename.pending_open = true;
1908
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001909 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001910 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001911
1912 entry_str_len = strlen(ttrace->entry_str);
1913 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1914 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001915 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001916
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001917 if (filename_len > (size_t)remaining_space) {
1918 filename += filename_len - remaining_space;
1919 filename_len = remaining_space;
1920 }
1921
1922 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1923 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1924 memmove(pos + filename_len, pos, to_move);
1925 memcpy(pos, filename, filename_len);
1926
1927 ttrace->filename.ptr = 0;
1928 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001929out_put:
1930 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001931out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001932 return 0;
1933}
1934
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001935static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001936 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001937 struct perf_sample *sample)
1938{
1939 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1940 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001941 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001942 sample->pid,
1943 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001944 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001945
1946 if (ttrace == NULL)
1947 goto out_dump;
1948
1949 ttrace->runtime_ms += runtime_ms;
1950 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001951out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001952 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001953 return 0;
1954
1955out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001956 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001957 evsel->name,
1958 perf_evsel__strval(evsel, sample, "comm"),
1959 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1960 runtime,
1961 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001962 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001963}
1964
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001965static int bpf_output__printer(enum binary_printer_ops op,
1966 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001967{
Wang Nan1d6c9402016-02-26 09:31:55 +00001968 unsigned char ch = (unsigned char)val;
1969
1970 switch (op) {
1971 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001972 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001973 case BINARY_PRINT_DATA_BEGIN:
1974 case BINARY_PRINT_LINE_BEGIN:
1975 case BINARY_PRINT_ADDR:
1976 case BINARY_PRINT_NUM_DATA:
1977 case BINARY_PRINT_NUM_PAD:
1978 case BINARY_PRINT_SEP:
1979 case BINARY_PRINT_CHAR_PAD:
1980 case BINARY_PRINT_LINE_END:
1981 case BINARY_PRINT_DATA_END:
1982 default:
1983 break;
1984 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001985
1986 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001987}
1988
1989static void bpf_output__fprintf(struct trace *trace,
1990 struct perf_sample *sample)
1991{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001992 binary__fprintf(sample->raw_data, sample->raw_size, 8,
1993 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00001994}
1995
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03001996static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1997 union perf_event *event __maybe_unused,
1998 struct perf_sample *sample)
1999{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002000 int callchain_ret = 0;
2001
2002 if (sample->callchain) {
2003 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2004 if (callchain_ret == 0) {
2005 if (callchain_cursor.nr < trace->min_stack)
2006 goto out;
2007 callchain_ret = 1;
2008 }
2009 }
2010
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03002011 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002012 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002013
2014 if (trace->trace_syscalls)
2015 fprintf(trace->output, "( ): ");
2016
2017 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002018
Wang Nan1d6c9402016-02-26 09:31:55 +00002019 if (perf_evsel__is_bpf_output(evsel)) {
2020 bpf_output__fprintf(trace, sample);
2021 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002022 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2023 trace__fprintf_sys_enter(trace, evsel, sample)) {
2024 event_format__fprintf(evsel->tp_format, sample->cpu,
2025 sample->raw_data, sample->raw_size,
2026 trace->output);
2027 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002028 }
2029
Changbin Du51125a22018-03-13 18:40:01 +08002030 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002031
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002032 if (callchain_ret > 0)
2033 trace__fprintf_callchain(trace, sample);
2034 else if (callchain_ret < 0)
2035 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2036out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002037 return 0;
2038}
2039
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002040static void print_location(FILE *f, struct perf_sample *sample,
2041 struct addr_location *al,
2042 bool print_dso, bool print_sym)
2043{
2044
Namhyung Kimbb963e12017-02-17 17:17:38 +09002045 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002046 fprintf(f, "%s@", al->map->dso->long_name);
2047
Namhyung Kimbb963e12017-02-17 17:17:38 +09002048 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002049 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002050 al->addr - al->sym->start);
2051 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002052 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002053 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002054 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002055}
2056
2057static int trace__pgfault(struct trace *trace,
2058 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002059 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002060 struct perf_sample *sample)
2061{
2062 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002063 struct addr_location al;
2064 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002065 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002066 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002067 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002068
2069 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002070
2071 if (sample->callchain) {
2072 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2073 if (callchain_ret == 0) {
2074 if (callchain_cursor.nr < trace->min_stack)
2075 goto out_put;
2076 callchain_ret = 1;
2077 }
2078 }
2079
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002080 ttrace = thread__trace(thread, trace->output);
2081 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002082 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002083
2084 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2085 ttrace->pfmaj++;
2086 else
2087 ttrace->pfmin++;
2088
2089 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002090 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002091
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002092 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002093
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002094 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002095
2096 fprintf(trace->output, "%sfault [",
2097 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2098 "maj" : "min");
2099
2100 print_location(trace->output, sample, &al, false, true);
2101
2102 fprintf(trace->output, "] => ");
2103
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002104 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002105
2106 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002107 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002108
2109 if (al.map)
2110 map_type = 'x';
2111 else
2112 map_type = '?';
2113 }
2114
2115 print_location(trace->output, sample, &al, true, false);
2116
2117 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002118
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002119 if (callchain_ret > 0)
2120 trace__fprintf_callchain(trace, sample);
2121 else if (callchain_ret < 0)
2122 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002123out:
2124 err = 0;
2125out_put:
2126 thread__put(thread);
2127 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002128}
2129
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002130static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002131 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002132 struct perf_sample *sample)
2133{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002134 /*
2135 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2136 * and don't use sample->time unconditionally, we may end up having
2137 * some other event in the future without PERF_SAMPLE_TIME for good
2138 * reason, i.e. we may not be interested in its timestamps, just in
2139 * it taking place, picking some piece of information when it
2140 * appears in our event stream (vfs_getname comes to mind).
2141 */
2142 if (trace->base_time == 0 && !trace->full_time &&
2143 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002144 trace->base_time = sample->time;
2145}
2146
David Ahern6810fc92013-08-28 22:29:52 -06002147static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002148 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002149 struct perf_sample *sample,
2150 struct perf_evsel *evsel,
2151 struct machine *machine __maybe_unused)
2152{
2153 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002154 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002155 int err = 0;
2156
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002157 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002158
David Ahernaa07df62016-11-25 09:29:52 -07002159 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2160 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002161 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002162
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002163 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002164
David Ahern31605652013-12-04 19:41:41 -07002165 if (handler) {
2166 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002167 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002168 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002169out:
2170 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002171 return err;
2172}
2173
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002174static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002175{
2176 unsigned int rec_argc, i, j;
2177 const char **rec_argv;
2178 const char * const record_args[] = {
2179 "record",
2180 "-R",
2181 "-m", "1024",
2182 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002183 };
2184
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002185 const char * const sc_args[] = { "-e", };
2186 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2187 const char * const majpf_args[] = { "-e", "major-faults" };
2188 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2189 const char * const minpf_args[] = { "-e", "minor-faults" };
2190 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2191
David Ahern9aca7f12013-12-04 19:41:39 -07002192 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002193 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2194 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002195 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2196
2197 if (rec_argv == NULL)
2198 return -ENOMEM;
2199
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002200 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002201 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002202 rec_argv[j++] = record_args[i];
2203
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002204 if (trace->trace_syscalls) {
2205 for (i = 0; i < sc_args_nr; i++)
2206 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002207
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002208 /* event string may be different for older kernels - e.g., RHEL6 */
2209 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2210 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2211 else if (is_valid_tracepoint("syscalls:sys_enter"))
2212 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2213 else {
2214 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002215 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002216 return -1;
2217 }
David Ahern9aca7f12013-12-04 19:41:39 -07002218 }
David Ahern9aca7f12013-12-04 19:41:39 -07002219
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002220 if (trace->trace_pgfaults & TRACE_PFMAJ)
2221 for (i = 0; i < majpf_args_nr; i++)
2222 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002223
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002224 if (trace->trace_pgfaults & TRACE_PFMIN)
2225 for (i = 0; i < minpf_args_nr; i++)
2226 rec_argv[j++] = minpf_args[i];
2227
2228 for (i = 0; i < (unsigned int)argc; i++)
2229 rec_argv[j++] = argv[i];
2230
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002231 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002232}
2233
David Ahernbf2575c2013-10-08 21:26:53 -06002234static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2235
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002236static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002237{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002238 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002239
2240 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002241 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002242
2243 if (perf_evsel__field(evsel, "pathname") == NULL) {
2244 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002245 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002246 }
2247
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002248 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002249 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002250 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002251}
2252
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002253static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002254{
2255 struct perf_evsel *evsel;
2256 struct perf_event_attr attr = {
2257 .type = PERF_TYPE_SOFTWARE,
2258 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002259 };
2260
2261 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002262 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002263
2264 event_attr_init(&attr);
2265
2266 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002267 if (evsel)
2268 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002269
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002270 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002271}
2272
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002273static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2274{
2275 const u32 type = event->header.type;
2276 struct perf_evsel *evsel;
2277
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002278 if (type != PERF_RECORD_SAMPLE) {
2279 trace__process_event(trace, trace->host, event, sample);
2280 return;
2281 }
2282
2283 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2284 if (evsel == NULL) {
2285 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2286 return;
2287 }
2288
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002289 trace__set_base_time(trace, evsel, sample);
2290
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002291 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2292 sample->raw_data == NULL) {
2293 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2294 perf_evsel__name(evsel), sample->tid,
2295 sample->cpu, sample->raw_size);
2296 } else {
2297 tracepoint_handler handler = evsel->handler;
2298 handler(trace, evsel, event, sample);
2299 }
2300}
2301
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002302static int trace__add_syscall_newtp(struct trace *trace)
2303{
2304 int ret = -1;
2305 struct perf_evlist *evlist = trace->evlist;
2306 struct perf_evsel *sys_enter, *sys_exit;
2307
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002308 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002309 if (sys_enter == NULL)
2310 goto out;
2311
2312 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2313 goto out_delete_sys_enter;
2314
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002315 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002316 if (sys_exit == NULL)
2317 goto out_delete_sys_enter;
2318
2319 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2320 goto out_delete_sys_exit;
2321
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002322 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2323 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2324
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002325 perf_evlist__add(evlist, sys_enter);
2326 perf_evlist__add(evlist, sys_exit);
2327
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002328 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002329 /*
2330 * We're interested only in the user space callchain
2331 * leading to the syscall, allow overriding that for
2332 * debugging reasons using --kernel_syscall_callchains
2333 */
2334 sys_exit->attr.exclude_callchain_kernel = 1;
2335 }
2336
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002337 trace->syscalls.events.sys_enter = sys_enter;
2338 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002339
2340 ret = 0;
2341out:
2342 return ret;
2343
2344out_delete_sys_exit:
2345 perf_evsel__delete_priv(sys_exit);
2346out_delete_sys_enter:
2347 perf_evsel__delete_priv(sys_enter);
2348 goto out;
2349}
2350
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002351static int trace__set_ev_qualifier_filter(struct trace *trace)
2352{
2353 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002354 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002355 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2356 trace->ev_qualifier_ids.nr,
2357 trace->ev_qualifier_ids.entries);
2358
2359 if (filter == NULL)
2360 goto out_enomem;
2361
Mathieu Poirier3541c032016-09-16 08:44:04 -06002362 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2363 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002364 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002365 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002366 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002367
2368 free(filter);
2369out:
2370 return err;
2371out_enomem:
2372 errno = ENOMEM;
2373 goto out;
2374}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002375
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002376static int trace__set_filter_loop_pids(struct trace *trace)
2377{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002378 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002379 pid_t pids[32] = {
2380 getpid(),
2381 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002382 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2383
2384 while (thread && nr < ARRAY_SIZE(pids)) {
2385 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2386
2387 if (parent == NULL)
2388 break;
2389
2390 if (!strcmp(thread__comm_str(parent), "sshd")) {
2391 pids[nr++] = parent->tid;
2392 break;
2393 }
2394 thread = parent;
2395 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002396
2397 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2398}
2399
Namhyung Kimf15eb532012-10-05 14:02:16 +09002400static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002401{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002402 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002403 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002404 int err = -1, i;
2405 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002406 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002407 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002408
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002409 trace->live = true;
2410
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002411 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002412 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002413
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002414 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002415 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002416
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002417 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2418 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2419 if (pgfault_maj == NULL)
2420 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002421 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002422 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002423 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002424
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002425 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2426 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2427 if (pgfault_min == NULL)
2428 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002429 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002430 perf_evlist__add(evlist, pgfault_min);
2431 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002432
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002433 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002434 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2435 trace__sched_stat_runtime))
2436 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002437
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002438 /*
2439 * If a global cgroup was set, apply it to all the events without an
2440 * explicit cgroup. I.e.:
2441 *
2442 * trace -G A -e sched:*switch
2443 *
2444 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2445 * _and_ sched:sched_switch to the 'A' cgroup, while:
2446 *
2447 * trace -e sched:*switch -G A
2448 *
2449 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2450 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2451 * a cgroup (on the root cgroup, sys wide, etc).
2452 *
2453 * Multiple cgroups:
2454 *
2455 * trace -G A -e sched:*switch -G B
2456 *
2457 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2458 * to the 'B' cgroup.
2459 *
2460 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2461 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2462 */
2463 if (trace->cgroup)
2464 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2465
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002466 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2467 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002468 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002469 goto out_delete_evlist;
2470 }
2471
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002472 err = trace__symbols_init(trace, evlist);
2473 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002474 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002475 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002476 }
2477
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002478 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002479
Namhyung Kimf15eb532012-10-05 14:02:16 +09002480 signal(SIGCHLD, sig_handler);
2481 signal(SIGINT, sig_handler);
2482
2483 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002484 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002485 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002486 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002487 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002488 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002489 }
2490 }
2491
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002492 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002493 if (err < 0)
2494 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002495
Wang Nanba504232016-02-26 09:31:54 +00002496 err = bpf__apply_obj_config();
2497 if (err) {
2498 char errbuf[BUFSIZ];
2499
2500 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2501 pr_err("ERROR: Apply config to BPF failed: %s\n",
2502 errbuf);
2503 goto out_error_open;
2504 }
2505
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002506 /*
2507 * Better not use !target__has_task() here because we need to cover the
2508 * case where no threads were specified in the command line, but a
2509 * workload was, and in that case we will fill in the thread_map when
2510 * we fork the workload in perf_evlist__prepare_workload.
2511 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002512 if (trace->filter_pids.nr > 0)
2513 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002514 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002515 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002516
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002517 if (err < 0)
2518 goto out_error_mem;
2519
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002520 if (trace->ev_qualifier_ids.nr > 0) {
2521 err = trace__set_ev_qualifier_filter(trace);
2522 if (err < 0)
2523 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002524
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002525 pr_debug("event qualifier tracepoint filter: %s\n",
2526 trace->syscalls.events.sys_exit->filter);
2527 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002528
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002529 err = perf_evlist__apply_filters(evlist, &evsel);
2530 if (err < 0)
2531 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002532
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002533 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002534 if (err < 0)
2535 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002536
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002537 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002538 perf_evlist__enable(evlist);
2539
Namhyung Kimf15eb532012-10-05 14:02:16 +09002540 if (forks)
2541 perf_evlist__start_workload(evlist);
2542
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002543 if (trace->opts.initial_delay) {
2544 usleep(trace->opts.initial_delay * 1000);
2545 perf_evlist__enable(evlist);
2546 }
2547
Jiri Olsae13798c2015-06-23 00:36:02 +02002548 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002549 evlist->threads->nr > 1 ||
2550 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002551
2552 /*
2553 * Now that we already used evsel->attr to ask the kernel to setup the
2554 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2555 * trace__resolve_callchain(), allowing per-event max-stack settings
2556 * to override an explicitely set --max-stack global setting.
2557 */
2558 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002559 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002560 evsel->attr.sample_max_stack == 0)
2561 evsel->attr.sample_max_stack = trace->max_stack;
2562 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002563again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002564 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002565
2566 for (i = 0; i < evlist->nr_mmaps; i++) {
2567 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002568 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002569
Kan Liangd7f55c62018-03-01 18:08:59 -05002570 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002571 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002572 continue;
2573
Kan Liang0019dc872018-03-06 10:36:06 -05002574 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002575 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002576
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002577 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002578
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002579 err = perf_evlist__parse_sample(evlist, event, &sample);
2580 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002581 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002582 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002583 }
2584
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002585 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002586next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002587 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002588
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002589 if (interrupted)
2590 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002591
2592 if (done && !draining) {
2593 perf_evlist__disable(evlist);
2594 draining = true;
2595 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002596 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002597 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002598 }
2599
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002600 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002601 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002602
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002603 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2604 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2605 draining = true;
2606
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002607 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002608 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002609 } else {
2610 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002611 }
2612
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002613out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002614 thread__zput(trace->current);
2615
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002616 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002617
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002618 if (!err) {
2619 if (trace->summary)
2620 trace__fprintf_thread_summary(trace, trace->output);
2621
2622 if (trace->show_tool_stats) {
2623 fprintf(trace->output, "Stats:\n "
2624 " vfs_getname : %" PRIu64 "\n"
2625 " proc_getname: %" PRIu64 "\n",
2626 trace->stats.vfs_getname,
2627 trace->stats.proc_getname);
2628 }
2629 }
David Ahernbf2575c2013-10-08 21:26:53 -06002630
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002631out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002632 trace__symbols__exit(trace);
2633
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002634 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002635 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002636 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002637 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002638 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002639{
2640 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002641
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002642out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002643 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002644 goto out_error;
2645
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002646out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002647 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002648 goto out_error;
2649
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002650out_error_mmap:
2651 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2652 goto out_error;
2653
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002654out_error_open:
2655 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2656
2657out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002658 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302659 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002660
2661out_error_apply_filters:
2662 fprintf(trace->output,
2663 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2664 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002665 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002666 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002667}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002668out_error_mem:
2669 fprintf(trace->output, "Not enough memory to run!\n");
2670 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002671
2672out_errno:
2673 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2674 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002675}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002676
David Ahern6810fc92013-08-28 22:29:52 -06002677static int trace__replay(struct trace *trace)
2678{
2679 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002680 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002681 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002682 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002683 .file = {
2684 .path = input_name,
2685 },
2686 .mode = PERF_DATA_MODE_READ,
2687 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002688 };
David Ahern6810fc92013-08-28 22:29:52 -06002689 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002690 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002691 int err = -1;
2692
2693 trace->tool.sample = trace__process_sample;
2694 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002695 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002696 trace->tool.comm = perf_event__process_comm;
2697 trace->tool.exit = perf_event__process_exit;
2698 trace->tool.fork = perf_event__process_fork;
2699 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302700 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002701 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302702 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002703
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002704 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002705 trace->tool.ordering_requires_timestamps = true;
2706
2707 /* add tid to output */
2708 trace->multiple_threads = true;
2709
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002710 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002711 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002712 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002713
David Ahernaa07df62016-11-25 09:29:52 -07002714 if (trace->opts.target.pid)
2715 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2716
2717 if (trace->opts.target.tid)
2718 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2719
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002720 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002721 goto out;
2722
David Ahern8fb598e2013-09-28 13:13:00 -06002723 trace->host = &session->machines.host;
2724
David Ahern6810fc92013-08-28 22:29:52 -06002725 err = perf_session__set_tracepoints_handlers(session, handlers);
2726 if (err)
2727 goto out;
2728
Namhyung Kim003824e2013-11-12 15:25:00 +09002729 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2730 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002731 /* older kernels have syscalls tp versus raw_syscalls */
2732 if (evsel == NULL)
2733 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2734 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002735
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002736 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002737 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002738 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002739 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2740 goto out;
2741 }
2742
2743 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2744 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002745 if (evsel == NULL)
2746 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2747 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002748 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002749 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002750 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002751 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002752 goto out;
2753 }
2754
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002755 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002756 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2757 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2758 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2759 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2760 evsel->handler = trace__pgfault;
2761 }
2762
David Ahern6810fc92013-08-28 22:29:52 -06002763 setup_pager();
2764
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002765 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002766 if (err)
2767 pr_err("Failed to process events, error %d", err);
2768
David Ahernbf2575c2013-10-08 21:26:53 -06002769 else if (trace->summary)
2770 trace__fprintf_thread_summary(trace, trace->output);
2771
David Ahern6810fc92013-08-28 22:29:52 -06002772out:
2773 perf_session__delete(session);
2774
2775 return err;
2776}
2777
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002778static size_t trace__fprintf_threads_header(FILE *fp)
2779{
2780 size_t printed;
2781
Pekka Enberg99ff7152013-11-12 16:42:14 +02002782 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002783
2784 return printed;
2785}
2786
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002787DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2788 struct stats *stats;
2789 double msecs;
2790 int syscall;
2791)
2792{
2793 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2794 struct stats *stats = source->priv;
2795
2796 entry->syscall = source->i;
2797 entry->stats = stats;
2798 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2799}
2800
David Ahernbf2575c2013-10-08 21:26:53 -06002801static size_t thread__dump_stats(struct thread_trace *ttrace,
2802 struct trace *trace, FILE *fp)
2803{
David Ahernbf2575c2013-10-08 21:26:53 -06002804 size_t printed = 0;
2805 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002806 struct rb_node *nd;
2807 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002808
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002809 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002810 return 0;
2811
2812 printed += fprintf(fp, "\n");
2813
Milian Wolff834fd462015-08-06 11:24:29 +02002814 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2815 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2816 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002817
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002818 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002819 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002820 if (stats) {
2821 double min = (double)(stats->min) / NSEC_PER_MSEC;
2822 double max = (double)(stats->max) / NSEC_PER_MSEC;
2823 double avg = avg_stats(stats);
2824 double pct;
2825 u64 n = (u64) stats->n;
2826
2827 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2828 avg /= NSEC_PER_MSEC;
2829
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002830 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002831 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002832 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002833 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002834 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002835 }
David Ahernbf2575c2013-10-08 21:26:53 -06002836 }
2837
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002838 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002839 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002840
2841 return printed;
2842}
2843
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002844static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002845{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002846 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002847 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002848 double ratio;
2849
2850 if (ttrace == NULL)
2851 return 0;
2852
2853 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2854
Pekka Enberg15e65c62013-11-14 18:43:30 +02002855 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002856 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002857 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002858 if (ttrace->pfmaj)
2859 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2860 if (ttrace->pfmin)
2861 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002862 if (trace->sched)
2863 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2864 else if (fputc('\n', fp) != EOF)
2865 ++printed;
2866
David Ahernbf2575c2013-10-08 21:26:53 -06002867 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002868
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002869 return printed;
2870}
David Ahern896cbb52013-09-28 13:12:59 -06002871
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002872static unsigned long thread__nr_events(struct thread_trace *ttrace)
2873{
2874 return ttrace ? ttrace->nr_events : 0;
2875}
2876
2877DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2878 struct thread *thread;
2879)
2880{
2881 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002882}
2883
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002884static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2885{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002886 size_t printed = trace__fprintf_threads_header(fp);
2887 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002888 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002889
Kan Liang91e467b2017-09-10 19:23:14 -07002890 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2891 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2892
2893 if (threads == NULL) {
2894 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2895 return 0;
2896 }
2897
2898 resort_rb__for_each_entry(nd, threads)
2899 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2900
2901 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002902 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002903 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002904}
2905
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002906static int trace__set_duration(const struct option *opt, const char *str,
2907 int unset __maybe_unused)
2908{
2909 struct trace *trace = opt->value;
2910
2911 trace->duration_filter = atof(str);
2912 return 0;
2913}
2914
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002915static int trace__set_filter_pids(const struct option *opt, const char *str,
2916 int unset __maybe_unused)
2917{
2918 int ret = -1;
2919 size_t i;
2920 struct trace *trace = opt->value;
2921 /*
2922 * FIXME: introduce a intarray class, plain parse csv and create a
2923 * { int nr, int entries[] } struct...
2924 */
2925 struct intlist *list = intlist__new(str);
2926
2927 if (list == NULL)
2928 return -1;
2929
2930 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2931 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2932
2933 if (trace->filter_pids.entries == NULL)
2934 goto out;
2935
2936 trace->filter_pids.entries[0] = getpid();
2937
2938 for (i = 1; i < trace->filter_pids.nr; ++i)
2939 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2940
2941 intlist__delete(list);
2942 ret = 0;
2943out:
2944 return ret;
2945}
2946
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002947static int trace__open_output(struct trace *trace, const char *filename)
2948{
2949 struct stat st;
2950
2951 if (!stat(filename, &st) && st.st_size) {
2952 char oldname[PATH_MAX];
2953
2954 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2955 unlink(oldname);
2956 rename(filename, oldname);
2957 }
2958
2959 trace->output = fopen(filename, "w");
2960
2961 return trace->output == NULL ? -errno : 0;
2962}
2963
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002964static int parse_pagefaults(const struct option *opt, const char *str,
2965 int unset __maybe_unused)
2966{
2967 int *trace_pgfaults = opt->value;
2968
2969 if (strcmp(str, "all") == 0)
2970 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2971 else if (strcmp(str, "maj") == 0)
2972 *trace_pgfaults |= TRACE_PFMAJ;
2973 else if (strcmp(str, "min") == 0)
2974 *trace_pgfaults |= TRACE_PFMIN;
2975 else
2976 return -1;
2977
2978 return 0;
2979}
2980
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002981static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2982{
2983 struct perf_evsel *evsel;
2984
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002985 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002986 evsel->handler = handler;
2987}
2988
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03002989static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist)
2990{
2991 struct perf_evsel *evsel;
2992
2993 evlist__for_each_entry(evlist, evsel) {
2994 if (evsel->priv || !evsel->tp_format)
2995 continue;
2996
2997 if (strcmp(evsel->tp_format->system, "syscalls"))
2998 continue;
2999
3000 if (perf_evsel__init_syscall_tp(evsel))
3001 return -1;
3002
3003 if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
3004 struct syscall_tp *sc = evsel->priv;
3005
3006 if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
3007 return -1;
3008 } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
3009 struct syscall_tp *sc = evsel->priv;
3010
3011 if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
3012 return -1;
3013 }
3014 }
3015
3016 return 0;
3017}
3018
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003019/*
3020 * XXX: Hackish, just splitting the combined -e+--event (syscalls
3021 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
3022 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
3023 *
3024 * It'd be better to introduce a parse_options() variant that would return a
3025 * list with the terms it didn't match to an event...
3026 */
3027static int trace__parse_events_option(const struct option *opt, const char *str,
3028 int unset __maybe_unused)
3029{
3030 struct trace *trace = (struct trace *)opt->value;
3031 const char *s = str;
3032 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003033 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003034 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
3035 char group_name[PATH_MAX];
3036
3037 if (strace_groups_dir == NULL)
3038 return -1;
3039
3040 if (*s == '!') {
3041 ++s;
3042 trace->not_ev_qualifier = true;
3043 }
3044
3045 while (1) {
3046 if ((sep = strchr(s, ',')) != NULL)
3047 *sep = '\0';
3048
3049 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003050 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3051 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003052 list = 1;
3053 } else {
3054 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3055 if (access(group_name, R_OK) == 0)
3056 list = 1;
3057 }
3058
3059 if (lists[list]) {
3060 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3061 } else {
3062 lists[list] = malloc(len);
3063 if (lists[list] == NULL)
3064 goto out;
3065 strcpy(lists[list], s);
3066 }
3067
3068 if (!sep)
3069 break;
3070
3071 *sep = ',';
3072 s = sep + 1;
3073 }
3074
3075 if (lists[1] != NULL) {
3076 struct strlist_config slist_config = {
3077 .dirname = strace_groups_dir,
3078 };
3079
3080 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3081 if (trace->ev_qualifier == NULL) {
3082 fputs("Not enough memory to parse event qualifier", trace->output);
3083 goto out;
3084 }
3085
3086 if (trace__validate_ev_qualifier(trace))
3087 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003088 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003089 }
3090
3091 err = 0;
3092
3093 if (lists[0]) {
3094 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3095 "event selector. use 'perf list' to list available events",
3096 parse_events_option);
3097 err = parse_events_option(&o, lists[0], 0);
3098 }
3099out:
3100 if (sep)
3101 *sep = ',';
3102
3103 return err;
3104}
3105
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003106static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3107{
3108 struct trace *trace = opt->value;
3109
3110 if (!list_empty(&trace->evlist->entries))
3111 return parse_cgroups(opt, str, unset);
3112
3113 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3114
3115 return 0;
3116}
3117
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003118int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003119{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003120 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003121 "perf trace [<options>] [<command>]",
3122 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003123 "perf trace record [<options>] [<command>]",
3124 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003125 NULL
3126 };
3127 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003128 .syscalls = {
3129 . max = -1,
3130 },
3131 .opts = {
3132 .target = {
3133 .uid = UINT_MAX,
3134 .uses_mmap = true,
3135 },
3136 .user_freq = UINT_MAX,
3137 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003138 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003139 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003140 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003141 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003142 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003143 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003144 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003145 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003146 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003147 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003148 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003149 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003150 OPT_CALLBACK('e', "event", &trace, "event",
3151 "event/syscall selector. use 'perf list' to list available events",
3152 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003153 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3154 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003155 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003156 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3157 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003158 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003159 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003160 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3161 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003162 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003163 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003164 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3165 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003166 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003167 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003168 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003169 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003170 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003171 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003172 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3173 "number of mmap data pages",
3174 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003175 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003176 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003177 OPT_CALLBACK(0, "duration", &trace, "float",
3178 "show only events with duration > N.M ms",
3179 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003180 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003181 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003182 OPT_BOOLEAN('T', "time", &trace.full_time,
3183 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003184 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3185 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003186 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3187 "Show only syscall summary with statistics"),
3188 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3189 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003190 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3191 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003192 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003193 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003194 OPT_CALLBACK(0, "call-graph", &trace.opts,
3195 "record_mode[,record_size]", record_callchain_help,
3196 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003197 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3198 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003199 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3200 "Set the minimum stack depth when parsing the callchain, "
3201 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003202 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3203 "Set the maximum stack depth when parsing the callchain, "
3204 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003205 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003206 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3207 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003208 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3209 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003210 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3211 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003212 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3213 "ms to wait before starting measurement after program "
3214 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003215 OPT_END()
3216 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003217 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003218 bool mmap_pages_user_set = true;
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003219 struct perf_evsel *evsel;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003220 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003221 int err = -1;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003222 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003223
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003224 signal(SIGSEGV, sighandler_dump_stack);
3225 signal(SIGFPE, sighandler_dump_stack);
3226
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003227 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003228 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003229
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003230 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003231 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003232 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003233 goto out;
3234 }
3235
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003236 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3237 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003238
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003239 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3240 usage_with_options_msg(trace_usage, trace_options,
3241 "cgroup monitoring only available in system-wide mode");
3242 }
3243
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003244 evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__");
3245 if (IS_ERR(evsel)) {
3246 bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf));
Arnaldo Carvalho de Meloe0b6d2e2018-08-07 15:40:13 -03003247 pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf);
3248 goto out;
3249 }
3250
Wang Nand7888572016-04-08 15:07:24 +00003251 err = bpf__setup_stdout(trace.evlist);
3252 if (err) {
3253 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3254 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3255 goto out;
3256 }
3257
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003258 err = -1;
3259
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003260 if (trace.trace_pgfaults) {
3261 trace.opts.sample_address = true;
3262 trace.opts.sample_time = true;
3263 }
3264
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003265 if (trace.opts.mmap_pages == UINT_MAX)
3266 mmap_pages_user_set = false;
3267
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003268 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003269 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003270 max_stack_user_set = false;
3271 }
3272
3273#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003274 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003275 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003276 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003277#endif
3278
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003279 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003280 if (!mmap_pages_user_set && geteuid() == 0)
3281 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3282
Milian Wolff566a0882016-04-08 13:34:15 +02003283 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003284 }
Milian Wolff566a0882016-04-08 13:34:15 +02003285
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003286 if (trace.evlist->nr_entries > 0) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003287 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003288 if (evlist__set_syscall_tp_fields(trace.evlist)) {
3289 perror("failed to set syscalls:* tracepoint fields");
3290 goto out;
3291 }
3292 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003293
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003294 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3295 return trace__record(&trace, argc-1, &argv[1]);
3296
3297 /* summary_only implies summary option, but don't overwrite summary if set */
3298 if (trace.summary_only)
3299 trace.summary = trace.summary_only;
3300
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003301 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3302 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003303 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003304 }
3305
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003306 if (output_name != NULL) {
3307 err = trace__open_output(&trace, output_name);
3308 if (err < 0) {
3309 perror("failed to create output file");
3310 goto out;
3311 }
3312 }
3313
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003314 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003315 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003316 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003317 fprintf(trace.output, "%s", bf);
3318 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003319 }
3320
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003321 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003322 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003323 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003324 fprintf(trace.output, "%s", bf);
3325 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003326 }
3327
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003328 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003329 trace.opts.target.system_wide = true;
3330
David Ahern6810fc92013-08-28 22:29:52 -06003331 if (input_name)
3332 err = trace__replay(&trace);
3333 else
3334 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003335
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003336out_close:
3337 if (output_name != NULL)
3338 fclose(trace.output);
3339out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003340 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003341}