1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * builtin-trace.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Builtin 'trace' command:
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Display a continuously updated trace of any workload, CPU, specific PID,
7*4882a593Smuzhiyun * system wide, etc. Default format is loosely strace like, but any other
8*4882a593Smuzhiyun * event may be specified using --event.
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * Initially based on the 'trace' prototype by Thomas Gleixner:
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "util/record.h"
18*4882a593Smuzhiyun #include <traceevent/event-parse.h>
19*4882a593Smuzhiyun #include <api/fs/tracing_path.h>
20*4882a593Smuzhiyun #include <bpf/bpf.h>
21*4882a593Smuzhiyun #include "util/bpf_map.h"
22*4882a593Smuzhiyun #include "util/rlimit.h"
23*4882a593Smuzhiyun #include "builtin.h"
24*4882a593Smuzhiyun #include "util/cgroup.h"
25*4882a593Smuzhiyun #include "util/color.h"
26*4882a593Smuzhiyun #include "util/config.h"
27*4882a593Smuzhiyun #include "util/debug.h"
28*4882a593Smuzhiyun #include "util/dso.h"
29*4882a593Smuzhiyun #include "util/env.h"
30*4882a593Smuzhiyun #include "util/event.h"
31*4882a593Smuzhiyun #include "util/evsel.h"
32*4882a593Smuzhiyun #include "util/evsel_fprintf.h"
33*4882a593Smuzhiyun #include "util/synthetic-events.h"
34*4882a593Smuzhiyun #include "util/evlist.h"
35*4882a593Smuzhiyun #include "util/evswitch.h"
36*4882a593Smuzhiyun #include "util/mmap.h"
37*4882a593Smuzhiyun #include <subcmd/pager.h>
38*4882a593Smuzhiyun #include <subcmd/exec-cmd.h>
39*4882a593Smuzhiyun #include "util/machine.h"
40*4882a593Smuzhiyun #include "util/map.h"
41*4882a593Smuzhiyun #include "util/symbol.h"
42*4882a593Smuzhiyun #include "util/path.h"
43*4882a593Smuzhiyun #include "util/session.h"
44*4882a593Smuzhiyun #include "util/thread.h"
45*4882a593Smuzhiyun #include <subcmd/parse-options.h>
46*4882a593Smuzhiyun #include "util/strlist.h"
47*4882a593Smuzhiyun #include "util/intlist.h"
48*4882a593Smuzhiyun #include "util/thread_map.h"
49*4882a593Smuzhiyun #include "util/stat.h"
50*4882a593Smuzhiyun #include "util/tool.h"
51*4882a593Smuzhiyun #include "util/util.h"
52*4882a593Smuzhiyun #include "trace/beauty/beauty.h"
53*4882a593Smuzhiyun #include "trace-event.h"
54*4882a593Smuzhiyun #include "util/parse-events.h"
55*4882a593Smuzhiyun #include "util/bpf-loader.h"
56*4882a593Smuzhiyun #include "callchain.h"
57*4882a593Smuzhiyun #include "print_binary.h"
58*4882a593Smuzhiyun #include "string2.h"
59*4882a593Smuzhiyun #include "syscalltbl.h"
60*4882a593Smuzhiyun #include "rb_resort.h"
61*4882a593Smuzhiyun #include "../perf.h"
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun #include <errno.h>
64*4882a593Smuzhiyun #include <inttypes.h>
65*4882a593Smuzhiyun #include <poll.h>
66*4882a593Smuzhiyun #include <signal.h>
67*4882a593Smuzhiyun #include <stdlib.h>
68*4882a593Smuzhiyun #include <string.h>
69*4882a593Smuzhiyun #include <linux/err.h>
70*4882a593Smuzhiyun #include <linux/filter.h>
71*4882a593Smuzhiyun #include <linux/kernel.h>
72*4882a593Smuzhiyun #include <linux/random.h>
73*4882a593Smuzhiyun #include <linux/stringify.h>
74*4882a593Smuzhiyun #include <linux/time64.h>
75*4882a593Smuzhiyun #include <linux/zalloc.h>
76*4882a593Smuzhiyun #include <fcntl.h>
77*4882a593Smuzhiyun #include <sys/sysmacros.h>
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun #include <linux/ctype.h>
80*4882a593Smuzhiyun #include <perf/mmap.h>
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun #ifndef O_CLOEXEC
83*4882a593Smuzhiyun # define O_CLOEXEC 02000000
84*4882a593Smuzhiyun #endif
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun #ifndef F_LINUX_SPECIFIC_BASE
87*4882a593Smuzhiyun # define F_LINUX_SPECIFIC_BASE 1024
88*4882a593Smuzhiyun #endif
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun /*
91*4882a593Smuzhiyun * strtoul: Go from a string to a value, i.e. for msr: MSR_FS_BASE to 0xc0000100
92*4882a593Smuzhiyun */
93*4882a593Smuzhiyun struct syscall_arg_fmt {
94*4882a593Smuzhiyun size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
95*4882a593Smuzhiyun bool (*strtoul)(char *bf, size_t size, struct syscall_arg *arg, u64 *val);
96*4882a593Smuzhiyun unsigned long (*mask_val)(struct syscall_arg *arg, unsigned long val);
97*4882a593Smuzhiyun void *parm;
98*4882a593Smuzhiyun const char *name;
99*4882a593Smuzhiyun u16 nr_entries; // for arrays
100*4882a593Smuzhiyun bool show_zero;
101*4882a593Smuzhiyun };
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun struct syscall_fmt {
104*4882a593Smuzhiyun const char *name;
105*4882a593Smuzhiyun const char *alias;
106*4882a593Smuzhiyun struct {
107*4882a593Smuzhiyun const char *sys_enter,
108*4882a593Smuzhiyun *sys_exit;
109*4882a593Smuzhiyun } bpf_prog_name;
110*4882a593Smuzhiyun struct syscall_arg_fmt arg[6];
111*4882a593Smuzhiyun u8 nr_args;
112*4882a593Smuzhiyun bool errpid;
113*4882a593Smuzhiyun bool timeout;
114*4882a593Smuzhiyun bool hexret;
115*4882a593Smuzhiyun };
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun struct trace {
118*4882a593Smuzhiyun struct perf_tool tool;
119*4882a593Smuzhiyun struct syscalltbl *sctbl;
120*4882a593Smuzhiyun struct {
121*4882a593Smuzhiyun struct syscall *table;
122*4882a593Smuzhiyun struct bpf_map *map;
123*4882a593Smuzhiyun struct { // per syscall BPF_MAP_TYPE_PROG_ARRAY
124*4882a593Smuzhiyun struct bpf_map *sys_enter,
125*4882a593Smuzhiyun *sys_exit;
126*4882a593Smuzhiyun } prog_array;
127*4882a593Smuzhiyun struct {
128*4882a593Smuzhiyun struct evsel *sys_enter,
129*4882a593Smuzhiyun *sys_exit,
130*4882a593Smuzhiyun *augmented;
131*4882a593Smuzhiyun } events;
132*4882a593Smuzhiyun struct bpf_program *unaugmented_prog;
133*4882a593Smuzhiyun } syscalls;
134*4882a593Smuzhiyun struct {
135*4882a593Smuzhiyun struct bpf_map *map;
136*4882a593Smuzhiyun } dump;
137*4882a593Smuzhiyun struct record_opts opts;
138*4882a593Smuzhiyun struct evlist *evlist;
139*4882a593Smuzhiyun struct machine *host;
140*4882a593Smuzhiyun struct thread *current;
141*4882a593Smuzhiyun struct bpf_object *bpf_obj;
142*4882a593Smuzhiyun struct cgroup *cgroup;
143*4882a593Smuzhiyun u64 base_time;
144*4882a593Smuzhiyun FILE *output;
145*4882a593Smuzhiyun unsigned long nr_events;
146*4882a593Smuzhiyun unsigned long nr_events_printed;
147*4882a593Smuzhiyun unsigned long max_events;
148*4882a593Smuzhiyun struct evswitch evswitch;
149*4882a593Smuzhiyun struct strlist *ev_qualifier;
150*4882a593Smuzhiyun struct {
151*4882a593Smuzhiyun size_t nr;
152*4882a593Smuzhiyun int *entries;
153*4882a593Smuzhiyun } ev_qualifier_ids;
154*4882a593Smuzhiyun struct {
155*4882a593Smuzhiyun size_t nr;
156*4882a593Smuzhiyun pid_t *entries;
157*4882a593Smuzhiyun struct bpf_map *map;
158*4882a593Smuzhiyun } filter_pids;
159*4882a593Smuzhiyun double duration_filter;
160*4882a593Smuzhiyun double runtime_ms;
161*4882a593Smuzhiyun struct {
162*4882a593Smuzhiyun u64 vfs_getname,
163*4882a593Smuzhiyun proc_getname;
164*4882a593Smuzhiyun } stats;
165*4882a593Smuzhiyun unsigned int max_stack;
166*4882a593Smuzhiyun unsigned int min_stack;
167*4882a593Smuzhiyun int raw_augmented_syscalls_args_size;
168*4882a593Smuzhiyun bool raw_augmented_syscalls;
169*4882a593Smuzhiyun bool fd_path_disabled;
170*4882a593Smuzhiyun bool sort_events;
171*4882a593Smuzhiyun bool not_ev_qualifier;
172*4882a593Smuzhiyun bool live;
173*4882a593Smuzhiyun bool full_time;
174*4882a593Smuzhiyun bool sched;
175*4882a593Smuzhiyun bool multiple_threads;
176*4882a593Smuzhiyun bool summary;
177*4882a593Smuzhiyun bool summary_only;
178*4882a593Smuzhiyun bool errno_summary;
179*4882a593Smuzhiyun bool failure_only;
180*4882a593Smuzhiyun bool show_comm;
181*4882a593Smuzhiyun bool print_sample;
182*4882a593Smuzhiyun bool show_tool_stats;
183*4882a593Smuzhiyun bool trace_syscalls;
184*4882a593Smuzhiyun bool libtraceevent_print;
185*4882a593Smuzhiyun bool kernel_syscallchains;
186*4882a593Smuzhiyun s16 args_alignment;
187*4882a593Smuzhiyun bool show_tstamp;
188*4882a593Smuzhiyun bool show_duration;
189*4882a593Smuzhiyun bool show_zeros;
190*4882a593Smuzhiyun bool show_arg_names;
191*4882a593Smuzhiyun bool show_string_prefix;
192*4882a593Smuzhiyun bool force;
193*4882a593Smuzhiyun bool vfs_getname;
194*4882a593Smuzhiyun int trace_pgfaults;
195*4882a593Smuzhiyun char *perfconfig_events;
196*4882a593Smuzhiyun struct {
197*4882a593Smuzhiyun struct ordered_events data;
198*4882a593Smuzhiyun u64 last;
199*4882a593Smuzhiyun } oe;
200*4882a593Smuzhiyun };
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun struct tp_field {
203*4882a593Smuzhiyun int offset;
204*4882a593Smuzhiyun union {
205*4882a593Smuzhiyun u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
206*4882a593Smuzhiyun void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
207*4882a593Smuzhiyun };
208*4882a593Smuzhiyun };
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun #define TP_UINT_FIELD(bits) \
211*4882a593Smuzhiyun static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
212*4882a593Smuzhiyun { \
213*4882a593Smuzhiyun u##bits value; \
214*4882a593Smuzhiyun memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
215*4882a593Smuzhiyun return value; \
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun TP_UINT_FIELD(8);
219*4882a593Smuzhiyun TP_UINT_FIELD(16);
220*4882a593Smuzhiyun TP_UINT_FIELD(32);
221*4882a593Smuzhiyun TP_UINT_FIELD(64);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun #define TP_UINT_FIELD__SWAPPED(bits) \
224*4882a593Smuzhiyun static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
225*4882a593Smuzhiyun { \
226*4882a593Smuzhiyun u##bits value; \
227*4882a593Smuzhiyun memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
228*4882a593Smuzhiyun return bswap_##bits(value);\
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun TP_UINT_FIELD__SWAPPED(16);
232*4882a593Smuzhiyun TP_UINT_FIELD__SWAPPED(32);
233*4882a593Smuzhiyun TP_UINT_FIELD__SWAPPED(64);
234*4882a593Smuzhiyun
__tp_field__init_uint(struct tp_field * field,int size,int offset,bool needs_swap)235*4882a593Smuzhiyun static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun field->offset = offset;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun switch (size) {
240*4882a593Smuzhiyun case 1:
241*4882a593Smuzhiyun field->integer = tp_field__u8;
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun case 2:
244*4882a593Smuzhiyun field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
245*4882a593Smuzhiyun break;
246*4882a593Smuzhiyun case 4:
247*4882a593Smuzhiyun field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
248*4882a593Smuzhiyun break;
249*4882a593Smuzhiyun case 8:
250*4882a593Smuzhiyun field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
251*4882a593Smuzhiyun break;
252*4882a593Smuzhiyun default:
253*4882a593Smuzhiyun return -1;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun return 0;
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun
tp_field__init_uint(struct tp_field * field,struct tep_format_field * format_field,bool needs_swap)259*4882a593Smuzhiyun static int tp_field__init_uint(struct tp_field *field, struct tep_format_field *format_field, bool needs_swap)
260*4882a593Smuzhiyun {
261*4882a593Smuzhiyun return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
tp_field__ptr(struct tp_field * field,struct perf_sample * sample)264*4882a593Smuzhiyun static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun return sample->raw_data + field->offset;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
__tp_field__init_ptr(struct tp_field * field,int offset)269*4882a593Smuzhiyun static int __tp_field__init_ptr(struct tp_field *field, int offset)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun field->offset = offset;
272*4882a593Smuzhiyun field->pointer = tp_field__ptr;
273*4882a593Smuzhiyun return 0;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
tp_field__init_ptr(struct tp_field * field,struct tep_format_field * format_field)276*4882a593Smuzhiyun static int tp_field__init_ptr(struct tp_field *field, struct tep_format_field *format_field)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun return __tp_field__init_ptr(field, format_field->offset);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun struct syscall_tp {
282*4882a593Smuzhiyun struct tp_field id;
283*4882a593Smuzhiyun union {
284*4882a593Smuzhiyun struct tp_field args, ret;
285*4882a593Smuzhiyun };
286*4882a593Smuzhiyun };
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun /*
289*4882a593Smuzhiyun * The evsel->priv as used by 'perf trace'
290*4882a593Smuzhiyun * sc: for raw_syscalls:sys_{enter,exit} and syscalls:sys_{enter,exit}_SYSCALLNAME
291*4882a593Smuzhiyun * fmt: for all the other tracepoints
292*4882a593Smuzhiyun */
293*4882a593Smuzhiyun struct evsel_trace {
294*4882a593Smuzhiyun struct syscall_tp sc;
295*4882a593Smuzhiyun struct syscall_arg_fmt *fmt;
296*4882a593Smuzhiyun };
297*4882a593Smuzhiyun
evsel_trace__new(void)298*4882a593Smuzhiyun static struct evsel_trace *evsel_trace__new(void)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun return zalloc(sizeof(struct evsel_trace));
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
evsel_trace__delete(struct evsel_trace * et)303*4882a593Smuzhiyun static void evsel_trace__delete(struct evsel_trace *et)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun if (et == NULL)
306*4882a593Smuzhiyun return;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun zfree(&et->fmt);
309*4882a593Smuzhiyun free(et);
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun /*
313*4882a593Smuzhiyun * Used with raw_syscalls:sys_{enter,exit} and with the
314*4882a593Smuzhiyun * syscalls:sys_{enter,exit}_SYSCALL tracepoints
315*4882a593Smuzhiyun */
__evsel__syscall_tp(struct evsel * evsel)316*4882a593Smuzhiyun static inline struct syscall_tp *__evsel__syscall_tp(struct evsel *evsel)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun struct evsel_trace *et = evsel->priv;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun return &et->sc;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
evsel__syscall_tp(struct evsel * evsel)323*4882a593Smuzhiyun static struct syscall_tp *evsel__syscall_tp(struct evsel *evsel)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun if (evsel->priv == NULL) {
326*4882a593Smuzhiyun evsel->priv = evsel_trace__new();
327*4882a593Smuzhiyun if (evsel->priv == NULL)
328*4882a593Smuzhiyun return NULL;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun return __evsel__syscall_tp(evsel);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun /*
335*4882a593Smuzhiyun * Used with all the other tracepoints.
336*4882a593Smuzhiyun */
__evsel__syscall_arg_fmt(struct evsel * evsel)337*4882a593Smuzhiyun static inline struct syscall_arg_fmt *__evsel__syscall_arg_fmt(struct evsel *evsel)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun struct evsel_trace *et = evsel->priv;
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun return et->fmt;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
evsel__syscall_arg_fmt(struct evsel * evsel)344*4882a593Smuzhiyun static struct syscall_arg_fmt *evsel__syscall_arg_fmt(struct evsel *evsel)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun struct evsel_trace *et = evsel->priv;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun if (evsel->priv == NULL) {
349*4882a593Smuzhiyun et = evsel->priv = evsel_trace__new();
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun if (et == NULL)
352*4882a593Smuzhiyun return NULL;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun if (et->fmt == NULL) {
356*4882a593Smuzhiyun et->fmt = calloc(evsel->tp_format->format.nr_fields, sizeof(struct syscall_arg_fmt));
357*4882a593Smuzhiyun if (et->fmt == NULL)
358*4882a593Smuzhiyun goto out_delete;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun return __evsel__syscall_arg_fmt(evsel);
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun out_delete:
364*4882a593Smuzhiyun evsel_trace__delete(evsel->priv);
365*4882a593Smuzhiyun evsel->priv = NULL;
366*4882a593Smuzhiyun return NULL;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
evsel__init_tp_uint_field(struct evsel * evsel,struct tp_field * field,const char * name)369*4882a593Smuzhiyun static int evsel__init_tp_uint_field(struct evsel *evsel, struct tp_field *field, const char *name)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct tep_format_field *format_field = evsel__field(evsel, name);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (format_field == NULL)
374*4882a593Smuzhiyun return -1;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun return tp_field__init_uint(field, format_field, evsel->needs_swap);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun #define perf_evsel__init_sc_tp_uint_field(evsel, name) \
380*4882a593Smuzhiyun ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
381*4882a593Smuzhiyun evsel__init_tp_uint_field(evsel, &sc->name, #name); })
382*4882a593Smuzhiyun
evsel__init_tp_ptr_field(struct evsel * evsel,struct tp_field * field,const char * name)383*4882a593Smuzhiyun static int evsel__init_tp_ptr_field(struct evsel *evsel, struct tp_field *field, const char *name)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun struct tep_format_field *format_field = evsel__field(evsel, name);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if (format_field == NULL)
388*4882a593Smuzhiyun return -1;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun return tp_field__init_ptr(field, format_field);
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun #define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
394*4882a593Smuzhiyun ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\
395*4882a593Smuzhiyun evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
396*4882a593Smuzhiyun
evsel__delete_priv(struct evsel * evsel)397*4882a593Smuzhiyun static void evsel__delete_priv(struct evsel *evsel)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun zfree(&evsel->priv);
400*4882a593Smuzhiyun evsel__delete(evsel);
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun
evsel__init_syscall_tp(struct evsel * evsel)403*4882a593Smuzhiyun static int evsel__init_syscall_tp(struct evsel *evsel)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun struct syscall_tp *sc = evsel__syscall_tp(evsel);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun if (sc != NULL) {
408*4882a593Smuzhiyun if (evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr") &&
409*4882a593Smuzhiyun evsel__init_tp_uint_field(evsel, &sc->id, "nr"))
410*4882a593Smuzhiyun return -ENOENT;
411*4882a593Smuzhiyun return 0;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return -ENOMEM;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
evsel__init_augmented_syscall_tp(struct evsel * evsel,struct evsel * tp)417*4882a593Smuzhiyun static int evsel__init_augmented_syscall_tp(struct evsel *evsel, struct evsel *tp)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun struct syscall_tp *sc = evsel__syscall_tp(evsel);
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun if (sc != NULL) {
422*4882a593Smuzhiyun struct tep_format_field *syscall_id = evsel__field(tp, "id");
423*4882a593Smuzhiyun if (syscall_id == NULL)
424*4882a593Smuzhiyun syscall_id = evsel__field(tp, "__syscall_nr");
425*4882a593Smuzhiyun if (syscall_id == NULL ||
426*4882a593Smuzhiyun __tp_field__init_uint(&sc->id, syscall_id->size, syscall_id->offset, evsel->needs_swap))
427*4882a593Smuzhiyun return -EINVAL;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun return 0;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun return -ENOMEM;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
evsel__init_augmented_syscall_tp_args(struct evsel * evsel)435*4882a593Smuzhiyun static int evsel__init_augmented_syscall_tp_args(struct evsel *evsel)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun struct syscall_tp *sc = __evsel__syscall_tp(evsel);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
evsel__init_augmented_syscall_tp_ret(struct evsel * evsel)442*4882a593Smuzhiyun static int evsel__init_augmented_syscall_tp_ret(struct evsel *evsel)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun struct syscall_tp *sc = __evsel__syscall_tp(evsel);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun return __tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
evsel__init_raw_syscall_tp(struct evsel * evsel,void * handler)449*4882a593Smuzhiyun static int evsel__init_raw_syscall_tp(struct evsel *evsel, void *handler)
450*4882a593Smuzhiyun {
451*4882a593Smuzhiyun if (evsel__syscall_tp(evsel) != NULL) {
452*4882a593Smuzhiyun if (perf_evsel__init_sc_tp_uint_field(evsel, id))
453*4882a593Smuzhiyun return -ENOENT;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun evsel->handler = handler;
456*4882a593Smuzhiyun return 0;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun return -ENOMEM;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
perf_evsel__raw_syscall_newtp(const char * direction,void * handler)462*4882a593Smuzhiyun static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun struct evsel *evsel = evsel__newtp("raw_syscalls", direction);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
467*4882a593Smuzhiyun if (IS_ERR(evsel))
468*4882a593Smuzhiyun evsel = evsel__newtp("syscalls", direction);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (IS_ERR(evsel))
471*4882a593Smuzhiyun return NULL;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun if (evsel__init_raw_syscall_tp(evsel, handler))
474*4882a593Smuzhiyun goto out_delete;
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun return evsel;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun out_delete:
479*4882a593Smuzhiyun evsel__delete_priv(evsel);
480*4882a593Smuzhiyun return NULL;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun #define perf_evsel__sc_tp_uint(evsel, name, sample) \
484*4882a593Smuzhiyun ({ struct syscall_tp *fields = __evsel__syscall_tp(evsel); \
485*4882a593Smuzhiyun fields->name.integer(&fields->name, sample); })
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun #define perf_evsel__sc_tp_ptr(evsel, name, sample) \
488*4882a593Smuzhiyun ({ struct syscall_tp *fields = __evsel__syscall_tp(evsel); \
489*4882a593Smuzhiyun fields->name.pointer(&fields->name, sample); })
490*4882a593Smuzhiyun
strarray__scnprintf_suffix(struct strarray * sa,char * bf,size_t size,const char * intfmt,bool show_suffix,int val)491*4882a593Smuzhiyun size_t strarray__scnprintf_suffix(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_suffix, int val)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun int idx = val - sa->offset;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL) {
496*4882a593Smuzhiyun size_t printed = scnprintf(bf, size, intfmt, val);
497*4882a593Smuzhiyun if (show_suffix)
498*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sa->prefix);
499*4882a593Smuzhiyun return printed;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun return scnprintf(bf, size, "%s%s", sa->entries[idx], show_suffix ? sa->prefix : "");
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun
strarray__scnprintf(struct strarray * sa,char * bf,size_t size,const char * intfmt,bool show_prefix,int val)505*4882a593Smuzhiyun size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, bool show_prefix, int val)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun int idx = val - sa->offset;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL) {
510*4882a593Smuzhiyun size_t printed = scnprintf(bf, size, intfmt, val);
511*4882a593Smuzhiyun if (show_prefix)
512*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sa->prefix);
513*4882a593Smuzhiyun return printed;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun return scnprintf(bf, size, "%s%s", show_prefix ? sa->prefix : "", sa->entries[idx]);
517*4882a593Smuzhiyun }
518*4882a593Smuzhiyun
__syscall_arg__scnprintf_strarray(char * bf,size_t size,const char * intfmt,struct syscall_arg * arg)519*4882a593Smuzhiyun static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
520*4882a593Smuzhiyun const char *intfmt,
521*4882a593Smuzhiyun struct syscall_arg *arg)
522*4882a593Smuzhiyun {
523*4882a593Smuzhiyun return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->show_string_prefix, arg->val);
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun
syscall_arg__scnprintf_strarray(char * bf,size_t size,struct syscall_arg * arg)526*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
527*4882a593Smuzhiyun struct syscall_arg *arg)
528*4882a593Smuzhiyun {
529*4882a593Smuzhiyun return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun #define SCA_STRARRAY syscall_arg__scnprintf_strarray
533*4882a593Smuzhiyun
syscall_arg__strtoul_strarray(char * bf,size_t size,struct syscall_arg * arg,u64 * ret)534*4882a593Smuzhiyun bool syscall_arg__strtoul_strarray(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun return strarray__strtoul(arg->parm, bf, size, ret);
537*4882a593Smuzhiyun }
538*4882a593Smuzhiyun
syscall_arg__strtoul_strarray_flags(char * bf,size_t size,struct syscall_arg * arg,u64 * ret)539*4882a593Smuzhiyun bool syscall_arg__strtoul_strarray_flags(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
540*4882a593Smuzhiyun {
541*4882a593Smuzhiyun return strarray__strtoul_flags(arg->parm, bf, size, ret);
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun
syscall_arg__strtoul_strarrays(char * bf,size_t size,struct syscall_arg * arg,u64 * ret)544*4882a593Smuzhiyun bool syscall_arg__strtoul_strarrays(char *bf, size_t size, struct syscall_arg *arg, u64 *ret)
545*4882a593Smuzhiyun {
546*4882a593Smuzhiyun return strarrays__strtoul(arg->parm, bf, size, ret);
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun
syscall_arg__scnprintf_strarray_flags(char * bf,size_t size,struct syscall_arg * arg)549*4882a593Smuzhiyun size_t syscall_arg__scnprintf_strarray_flags(char *bf, size_t size, struct syscall_arg *arg)
550*4882a593Smuzhiyun {
551*4882a593Smuzhiyun return strarray__scnprintf_flags(arg->parm, bf, size, arg->show_string_prefix, arg->val);
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
strarrays__scnprintf(struct strarrays * sas,char * bf,size_t size,const char * intfmt,bool show_prefix,int val)554*4882a593Smuzhiyun size_t strarrays__scnprintf(struct strarrays *sas, char *bf, size_t size, const char *intfmt, bool show_prefix, int val)
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun size_t printed;
557*4882a593Smuzhiyun int i;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun for (i = 0; i < sas->nr_entries; ++i) {
560*4882a593Smuzhiyun struct strarray *sa = sas->entries[i];
561*4882a593Smuzhiyun int idx = val - sa->offset;
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun if (idx >= 0 && idx < sa->nr_entries) {
564*4882a593Smuzhiyun if (sa->entries[idx] == NULL)
565*4882a593Smuzhiyun break;
566*4882a593Smuzhiyun return scnprintf(bf, size, "%s%s", show_prefix ? sa->prefix : "", sa->entries[idx]);
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun printed = scnprintf(bf, size, intfmt, val);
571*4882a593Smuzhiyun if (show_prefix)
572*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, " /* %s??? */", sas->entries[0]->prefix);
573*4882a593Smuzhiyun return printed;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
strarray__strtoul(struct strarray * sa,char * bf,size_t size,u64 * ret)576*4882a593Smuzhiyun bool strarray__strtoul(struct strarray *sa, char *bf, size_t size, u64 *ret)
577*4882a593Smuzhiyun {
578*4882a593Smuzhiyun int i;
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun for (i = 0; i < sa->nr_entries; ++i) {
581*4882a593Smuzhiyun if (sa->entries[i] && strncmp(sa->entries[i], bf, size) == 0 && sa->entries[i][size] == '\0') {
582*4882a593Smuzhiyun *ret = sa->offset + i;
583*4882a593Smuzhiyun return true;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun return false;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
strarray__strtoul_flags(struct strarray * sa,char * bf,size_t size,u64 * ret)590*4882a593Smuzhiyun bool strarray__strtoul_flags(struct strarray *sa, char *bf, size_t size, u64 *ret)
591*4882a593Smuzhiyun {
592*4882a593Smuzhiyun u64 val = 0;
593*4882a593Smuzhiyun char *tok = bf, *sep, *end;
594*4882a593Smuzhiyun
595*4882a593Smuzhiyun *ret = 0;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun while (size != 0) {
598*4882a593Smuzhiyun int toklen = size;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun sep = memchr(tok, '|', size);
601*4882a593Smuzhiyun if (sep != NULL) {
602*4882a593Smuzhiyun size -= sep - tok + 1;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun end = sep - 1;
605*4882a593Smuzhiyun while (end > tok && isspace(*end))
606*4882a593Smuzhiyun --end;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun toklen = end - tok + 1;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun while (isspace(*tok))
612*4882a593Smuzhiyun ++tok;
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun if (isalpha(*tok) || *tok == '_') {
615*4882a593Smuzhiyun if (!strarray__strtoul(sa, tok, toklen, &val))
616*4882a593Smuzhiyun return false;
617*4882a593Smuzhiyun } else {
618*4882a593Smuzhiyun bool is_hexa = tok[0] == 0 && (tok[1] = 'x' || tok[1] == 'X');
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun val = strtoul(tok, NULL, is_hexa ? 16 : 0);
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun *ret |= (1 << (val - 1));
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun if (sep == NULL)
626*4882a593Smuzhiyun break;
627*4882a593Smuzhiyun tok = sep + 1;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun return true;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
strarrays__strtoul(struct strarrays * sas,char * bf,size_t size,u64 * ret)633*4882a593Smuzhiyun bool strarrays__strtoul(struct strarrays *sas, char *bf, size_t size, u64 *ret)
634*4882a593Smuzhiyun {
635*4882a593Smuzhiyun int i;
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun for (i = 0; i < sas->nr_entries; ++i) {
638*4882a593Smuzhiyun struct strarray *sa = sas->entries[i];
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun if (strarray__strtoul(sa, bf, size, ret))
641*4882a593Smuzhiyun return true;
642*4882a593Smuzhiyun }
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun return false;
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun
syscall_arg__scnprintf_strarrays(char * bf,size_t size,struct syscall_arg * arg)647*4882a593Smuzhiyun size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
648*4882a593Smuzhiyun struct syscall_arg *arg)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun return strarrays__scnprintf(arg->parm, bf, size, "%d", arg->show_string_prefix, arg->val);
651*4882a593Smuzhiyun }
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun #ifndef AT_FDCWD
654*4882a593Smuzhiyun #define AT_FDCWD -100
655*4882a593Smuzhiyun #endif
656*4882a593Smuzhiyun
syscall_arg__scnprintf_fd_at(char * bf,size_t size,struct syscall_arg * arg)657*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
658*4882a593Smuzhiyun struct syscall_arg *arg)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun int fd = arg->val;
661*4882a593Smuzhiyun const char *prefix = "AT_FD";
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun if (fd == AT_FDCWD)
664*4882a593Smuzhiyun return scnprintf(bf, size, "%s%s", arg->show_string_prefix ? prefix : "", "CWD");
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun return syscall_arg__scnprintf_fd(bf, size, arg);
667*4882a593Smuzhiyun }
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun #define SCA_FDAT syscall_arg__scnprintf_fd_at
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
672*4882a593Smuzhiyun struct syscall_arg *arg);
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun #define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
675*4882a593Smuzhiyun
syscall_arg__scnprintf_hex(char * bf,size_t size,struct syscall_arg * arg)676*4882a593Smuzhiyun size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun return scnprintf(bf, size, "%#lx", arg->val);
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
syscall_arg__scnprintf_ptr(char * bf,size_t size,struct syscall_arg * arg)681*4882a593Smuzhiyun size_t syscall_arg__scnprintf_ptr(char *bf, size_t size, struct syscall_arg *arg)
682*4882a593Smuzhiyun {
683*4882a593Smuzhiyun if (arg->val == 0)
684*4882a593Smuzhiyun return scnprintf(bf, size, "NULL");
685*4882a593Smuzhiyun return syscall_arg__scnprintf_hex(bf, size, arg);
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
syscall_arg__scnprintf_int(char * bf,size_t size,struct syscall_arg * arg)688*4882a593Smuzhiyun size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun return scnprintf(bf, size, "%d", arg->val);
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
syscall_arg__scnprintf_long(char * bf,size_t size,struct syscall_arg * arg)693*4882a593Smuzhiyun size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun return scnprintf(bf, size, "%ld", arg->val);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
syscall_arg__scnprintf_char_array(char * bf,size_t size,struct syscall_arg * arg)698*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_char_array(char *bf, size_t size, struct syscall_arg *arg)
699*4882a593Smuzhiyun {
700*4882a593Smuzhiyun // XXX Hey, maybe for sched:sched_switch prev/next comm fields we can
701*4882a593Smuzhiyun // fill missing comms using thread__set_comm()...
702*4882a593Smuzhiyun // here or in a special syscall_arg__scnprintf_pid_sched_tp...
703*4882a593Smuzhiyun return scnprintf(bf, size, "\"%-.*s\"", arg->fmt->nr_entries ?: arg->len, arg->val);
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun #define SCA_CHAR_ARRAY syscall_arg__scnprintf_char_array
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun static const char *bpf_cmd[] = {
709*4882a593Smuzhiyun "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
710*4882a593Smuzhiyun "MAP_GET_NEXT_KEY", "PROG_LOAD",
711*4882a593Smuzhiyun };
712*4882a593Smuzhiyun static DEFINE_STRARRAY(bpf_cmd, "BPF_");
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun static const char *fsmount_flags[] = {
715*4882a593Smuzhiyun [1] = "CLOEXEC",
716*4882a593Smuzhiyun };
717*4882a593Smuzhiyun static DEFINE_STRARRAY(fsmount_flags, "FSMOUNT_");
718*4882a593Smuzhiyun
719*4882a593Smuzhiyun #include "trace/beauty/generated/fsconfig_arrays.c"
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun static DEFINE_STRARRAY(fsconfig_cmds, "FSCONFIG_");
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
724*4882a593Smuzhiyun static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, "EPOLL_CTL_", 1);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
727*4882a593Smuzhiyun static DEFINE_STRARRAY(itimers, "ITIMER_");
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun static const char *keyctl_options[] = {
730*4882a593Smuzhiyun "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
731*4882a593Smuzhiyun "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
732*4882a593Smuzhiyun "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
733*4882a593Smuzhiyun "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
734*4882a593Smuzhiyun "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
735*4882a593Smuzhiyun };
736*4882a593Smuzhiyun static DEFINE_STRARRAY(keyctl_options, "KEYCTL_");
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun static const char *whences[] = { "SET", "CUR", "END",
739*4882a593Smuzhiyun #ifdef SEEK_DATA
740*4882a593Smuzhiyun "DATA",
741*4882a593Smuzhiyun #endif
742*4882a593Smuzhiyun #ifdef SEEK_HOLE
743*4882a593Smuzhiyun "HOLE",
744*4882a593Smuzhiyun #endif
745*4882a593Smuzhiyun };
746*4882a593Smuzhiyun static DEFINE_STRARRAY(whences, "SEEK_");
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun static const char *fcntl_cmds[] = {
749*4882a593Smuzhiyun "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
750*4882a593Smuzhiyun "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
751*4882a593Smuzhiyun "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
752*4882a593Smuzhiyun "GETOWNER_UIDS",
753*4882a593Smuzhiyun };
754*4882a593Smuzhiyun static DEFINE_STRARRAY(fcntl_cmds, "F_");
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun static const char *fcntl_linux_specific_cmds[] = {
757*4882a593Smuzhiyun "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
758*4882a593Smuzhiyun "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
759*4882a593Smuzhiyun "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
760*4882a593Smuzhiyun };
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, "F_", F_LINUX_SPECIFIC_BASE);
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun static struct strarray *fcntl_cmds_arrays[] = {
765*4882a593Smuzhiyun &strarray__fcntl_cmds,
766*4882a593Smuzhiyun &strarray__fcntl_linux_specific_cmds,
767*4882a593Smuzhiyun };
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun static DEFINE_STRARRAYS(fcntl_cmds_arrays);
770*4882a593Smuzhiyun
771*4882a593Smuzhiyun static const char *rlimit_resources[] = {
772*4882a593Smuzhiyun "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
773*4882a593Smuzhiyun "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
774*4882a593Smuzhiyun "RTTIME",
775*4882a593Smuzhiyun };
776*4882a593Smuzhiyun static DEFINE_STRARRAY(rlimit_resources, "RLIMIT_");
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
779*4882a593Smuzhiyun static DEFINE_STRARRAY(sighow, "SIG_");
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun static const char *clockid[] = {
782*4882a593Smuzhiyun "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
783*4882a593Smuzhiyun "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
784*4882a593Smuzhiyun "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
785*4882a593Smuzhiyun };
786*4882a593Smuzhiyun static DEFINE_STRARRAY(clockid, "CLOCK_");
787*4882a593Smuzhiyun
syscall_arg__scnprintf_access_mode(char * bf,size_t size,struct syscall_arg * arg)788*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
789*4882a593Smuzhiyun struct syscall_arg *arg)
790*4882a593Smuzhiyun {
791*4882a593Smuzhiyun bool show_prefix = arg->show_string_prefix;
792*4882a593Smuzhiyun const char *suffix = "_OK";
793*4882a593Smuzhiyun size_t printed = 0;
794*4882a593Smuzhiyun int mode = arg->val;
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun if (mode == F_OK) /* 0 */
797*4882a593Smuzhiyun return scnprintf(bf, size, "F%s", show_prefix ? suffix : "");
798*4882a593Smuzhiyun #define P_MODE(n) \
799*4882a593Smuzhiyun if (mode & n##_OK) { \
800*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s%s", #n, show_prefix ? suffix : ""); \
801*4882a593Smuzhiyun mode &= ~n##_OK; \
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun P_MODE(R);
805*4882a593Smuzhiyun P_MODE(W);
806*4882a593Smuzhiyun P_MODE(X);
807*4882a593Smuzhiyun #undef P_MODE
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun if (mode)
810*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun return printed;
813*4882a593Smuzhiyun }
814*4882a593Smuzhiyun
815*4882a593Smuzhiyun #define SCA_ACCMODE syscall_arg__scnprintf_access_mode
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
818*4882a593Smuzhiyun struct syscall_arg *arg);
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun #define SCA_FILENAME syscall_arg__scnprintf_filename
821*4882a593Smuzhiyun
syscall_arg__scnprintf_pipe_flags(char * bf,size_t size,struct syscall_arg * arg)822*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
823*4882a593Smuzhiyun struct syscall_arg *arg)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun bool show_prefix = arg->show_string_prefix;
826*4882a593Smuzhiyun const char *prefix = "O_";
827*4882a593Smuzhiyun int printed = 0, flags = arg->val;
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun #define P_FLAG(n) \
830*4882a593Smuzhiyun if (flags & O_##n) { \
831*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \
832*4882a593Smuzhiyun flags &= ~O_##n; \
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun P_FLAG(CLOEXEC);
836*4882a593Smuzhiyun P_FLAG(NONBLOCK);
837*4882a593Smuzhiyun #undef P_FLAG
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun if (flags)
840*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun return printed;
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun #define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun #ifndef GRND_NONBLOCK
848*4882a593Smuzhiyun #define GRND_NONBLOCK 0x0001
849*4882a593Smuzhiyun #endif
850*4882a593Smuzhiyun #ifndef GRND_RANDOM
851*4882a593Smuzhiyun #define GRND_RANDOM 0x0002
852*4882a593Smuzhiyun #endif
853*4882a593Smuzhiyun
syscall_arg__scnprintf_getrandom_flags(char * bf,size_t size,struct syscall_arg * arg)854*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
855*4882a593Smuzhiyun struct syscall_arg *arg)
856*4882a593Smuzhiyun {
857*4882a593Smuzhiyun bool show_prefix = arg->show_string_prefix;
858*4882a593Smuzhiyun const char *prefix = "GRND_";
859*4882a593Smuzhiyun int printed = 0, flags = arg->val;
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun #define P_FLAG(n) \
862*4882a593Smuzhiyun if (flags & GRND_##n) { \
863*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s%s%s", printed ? "|" : "", show_prefix ? prefix : "", #n); \
864*4882a593Smuzhiyun flags &= ~GRND_##n; \
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun P_FLAG(RANDOM);
868*4882a593Smuzhiyun P_FLAG(NONBLOCK);
869*4882a593Smuzhiyun #undef P_FLAG
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun if (flags)
872*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun return printed;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
877*4882a593Smuzhiyun #define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun #define STRARRAY(name, array) \
880*4882a593Smuzhiyun { .scnprintf = SCA_STRARRAY, \
881*4882a593Smuzhiyun .strtoul = STUL_STRARRAY, \
882*4882a593Smuzhiyun .parm = &strarray__##array, }
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun #define STRARRAY_FLAGS(name, array) \
885*4882a593Smuzhiyun { .scnprintf = SCA_STRARRAY_FLAGS, \
886*4882a593Smuzhiyun .strtoul = STUL_STRARRAY_FLAGS, \
887*4882a593Smuzhiyun .parm = &strarray__##array, }
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun #include "trace/beauty/arch_errno_names.c"
890*4882a593Smuzhiyun #include "trace/beauty/eventfd.c"
891*4882a593Smuzhiyun #include "trace/beauty/futex_op.c"
892*4882a593Smuzhiyun #include "trace/beauty/futex_val3.c"
893*4882a593Smuzhiyun #include "trace/beauty/mmap.c"
894*4882a593Smuzhiyun #include "trace/beauty/mode_t.c"
895*4882a593Smuzhiyun #include "trace/beauty/msg_flags.c"
896*4882a593Smuzhiyun #include "trace/beauty/open_flags.c"
897*4882a593Smuzhiyun #include "trace/beauty/perf_event_open.c"
898*4882a593Smuzhiyun #include "trace/beauty/pid.c"
899*4882a593Smuzhiyun #include "trace/beauty/sched_policy.c"
900*4882a593Smuzhiyun #include "trace/beauty/seccomp.c"
901*4882a593Smuzhiyun #include "trace/beauty/signum.c"
902*4882a593Smuzhiyun #include "trace/beauty/socket_type.c"
903*4882a593Smuzhiyun #include "trace/beauty/waitid_options.c"
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun static struct syscall_fmt syscall_fmts[] = {
906*4882a593Smuzhiyun { .name = "access",
907*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
908*4882a593Smuzhiyun { .name = "arch_prctl",
909*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_X86_ARCH_PRCTL_CODE, /* code */ },
910*4882a593Smuzhiyun [1] = { .scnprintf = SCA_PTR, /* arg2 */ }, }, },
911*4882a593Smuzhiyun { .name = "bind",
912*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_INT, /* fd */ },
913*4882a593Smuzhiyun [1] = { .scnprintf = SCA_SOCKADDR, /* umyaddr */ },
914*4882a593Smuzhiyun [2] = { .scnprintf = SCA_INT, /* addrlen */ }, }, },
915*4882a593Smuzhiyun { .name = "bpf",
916*4882a593Smuzhiyun .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
917*4882a593Smuzhiyun { .name = "brk", .hexret = true,
918*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_PTR, /* brk */ }, }, },
919*4882a593Smuzhiyun { .name = "clock_gettime",
920*4882a593Smuzhiyun .arg = { [0] = STRARRAY(clk_id, clockid), }, },
921*4882a593Smuzhiyun { .name = "clone", .errpid = true, .nr_args = 5,
922*4882a593Smuzhiyun .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
923*4882a593Smuzhiyun [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
924*4882a593Smuzhiyun [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
925*4882a593Smuzhiyun [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
926*4882a593Smuzhiyun [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
927*4882a593Smuzhiyun { .name = "close",
928*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
929*4882a593Smuzhiyun { .name = "connect",
930*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_INT, /* fd */ },
931*4882a593Smuzhiyun [1] = { .scnprintf = SCA_SOCKADDR, /* servaddr */ },
932*4882a593Smuzhiyun [2] = { .scnprintf = SCA_INT, /* addrlen */ }, }, },
933*4882a593Smuzhiyun { .name = "epoll_ctl",
934*4882a593Smuzhiyun .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
935*4882a593Smuzhiyun { .name = "eventfd2",
936*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
937*4882a593Smuzhiyun { .name = "fchmodat",
938*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
939*4882a593Smuzhiyun { .name = "fchownat",
940*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
941*4882a593Smuzhiyun { .name = "fcntl",
942*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
943*4882a593Smuzhiyun .strtoul = STUL_STRARRAYS,
944*4882a593Smuzhiyun .parm = &strarrays__fcntl_cmds_arrays,
945*4882a593Smuzhiyun .show_zero = true, },
946*4882a593Smuzhiyun [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
947*4882a593Smuzhiyun { .name = "flock",
948*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
949*4882a593Smuzhiyun { .name = "fsconfig",
950*4882a593Smuzhiyun .arg = { [1] = STRARRAY(cmd, fsconfig_cmds), }, },
951*4882a593Smuzhiyun { .name = "fsmount",
952*4882a593Smuzhiyun .arg = { [1] = STRARRAY_FLAGS(flags, fsmount_flags),
953*4882a593Smuzhiyun [2] = { .scnprintf = SCA_FSMOUNT_ATTR_FLAGS, /* attr_flags */ }, }, },
954*4882a593Smuzhiyun { .name = "fspick",
955*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
956*4882a593Smuzhiyun [1] = { .scnprintf = SCA_FILENAME, /* path */ },
957*4882a593Smuzhiyun [2] = { .scnprintf = SCA_FSPICK_FLAGS, /* flags */ }, }, },
958*4882a593Smuzhiyun { .name = "fstat", .alias = "newfstat", },
959*4882a593Smuzhiyun { .name = "fstatat", .alias = "newfstatat", },
960*4882a593Smuzhiyun { .name = "futex",
961*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
962*4882a593Smuzhiyun [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
963*4882a593Smuzhiyun { .name = "futimesat",
964*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
965*4882a593Smuzhiyun { .name = "getitimer",
966*4882a593Smuzhiyun .arg = { [0] = STRARRAY(which, itimers), }, },
967*4882a593Smuzhiyun { .name = "getpid", .errpid = true, },
968*4882a593Smuzhiyun { .name = "getpgid", .errpid = true, },
969*4882a593Smuzhiyun { .name = "getppid", .errpid = true, },
970*4882a593Smuzhiyun { .name = "getrandom",
971*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
972*4882a593Smuzhiyun { .name = "getrlimit",
973*4882a593Smuzhiyun .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
974*4882a593Smuzhiyun { .name = "gettid", .errpid = true, },
975*4882a593Smuzhiyun { .name = "ioctl",
976*4882a593Smuzhiyun .arg = {
977*4882a593Smuzhiyun #if defined(__i386__) || defined(__x86_64__)
978*4882a593Smuzhiyun /*
979*4882a593Smuzhiyun * FIXME: Make this available to all arches.
980*4882a593Smuzhiyun */
981*4882a593Smuzhiyun [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
982*4882a593Smuzhiyun [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
983*4882a593Smuzhiyun #else
984*4882a593Smuzhiyun [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
985*4882a593Smuzhiyun #endif
986*4882a593Smuzhiyun { .name = "kcmp", .nr_args = 5,
987*4882a593Smuzhiyun .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
988*4882a593Smuzhiyun [1] = { .name = "pid2", .scnprintf = SCA_PID, },
989*4882a593Smuzhiyun [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
990*4882a593Smuzhiyun [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
991*4882a593Smuzhiyun [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
992*4882a593Smuzhiyun { .name = "keyctl",
993*4882a593Smuzhiyun .arg = { [0] = STRARRAY(option, keyctl_options), }, },
994*4882a593Smuzhiyun { .name = "kill",
995*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
996*4882a593Smuzhiyun { .name = "linkat",
997*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
998*4882a593Smuzhiyun { .name = "lseek",
999*4882a593Smuzhiyun .arg = { [2] = STRARRAY(whence, whences), }, },
1000*4882a593Smuzhiyun { .name = "lstat", .alias = "newlstat", },
1001*4882a593Smuzhiyun { .name = "madvise",
1002*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
1003*4882a593Smuzhiyun [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
1004*4882a593Smuzhiyun { .name = "mkdirat",
1005*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1006*4882a593Smuzhiyun { .name = "mknodat",
1007*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
1008*4882a593Smuzhiyun { .name = "mmap", .hexret = true,
1009*4882a593Smuzhiyun /* The standard mmap maps to old_mmap on s390x */
1010*4882a593Smuzhiyun #if defined(__s390x__)
1011*4882a593Smuzhiyun .alias = "old_mmap",
1012*4882a593Smuzhiyun #endif
1013*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
1014*4882a593Smuzhiyun [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */
1015*4882a593Smuzhiyun .strtoul = STUL_STRARRAY_FLAGS,
1016*4882a593Smuzhiyun .parm = &strarray__mmap_flags, },
1017*4882a593Smuzhiyun [5] = { .scnprintf = SCA_HEX, /* offset */ }, }, },
1018*4882a593Smuzhiyun { .name = "mount",
1019*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FILENAME, /* dev_name */ },
1020*4882a593Smuzhiyun [3] = { .scnprintf = SCA_MOUNT_FLAGS, /* flags */
1021*4882a593Smuzhiyun .mask_val = SCAMV_MOUNT_FLAGS, /* flags */ }, }, },
1022*4882a593Smuzhiyun { .name = "move_mount",
1023*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* from_dfd */ },
1024*4882a593Smuzhiyun [1] = { .scnprintf = SCA_FILENAME, /* from_pathname */ },
1025*4882a593Smuzhiyun [2] = { .scnprintf = SCA_FDAT, /* to_dfd */ },
1026*4882a593Smuzhiyun [3] = { .scnprintf = SCA_FILENAME, /* to_pathname */ },
1027*4882a593Smuzhiyun [4] = { .scnprintf = SCA_MOVE_MOUNT_FLAGS, /* flags */ }, }, },
1028*4882a593Smuzhiyun { .name = "mprotect",
1029*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
1030*4882a593Smuzhiyun [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
1031*4882a593Smuzhiyun { .name = "mq_unlink",
1032*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
1033*4882a593Smuzhiyun { .name = "mremap", .hexret = true,
1034*4882a593Smuzhiyun .arg = { [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ }, }, },
1035*4882a593Smuzhiyun { .name = "name_to_handle_at",
1036*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1037*4882a593Smuzhiyun { .name = "newfstatat",
1038*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1039*4882a593Smuzhiyun { .name = "open",
1040*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
1041*4882a593Smuzhiyun { .name = "open_by_handle_at",
1042*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
1043*4882a593Smuzhiyun [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
1044*4882a593Smuzhiyun { .name = "openat",
1045*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
1046*4882a593Smuzhiyun [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
1047*4882a593Smuzhiyun { .name = "perf_event_open",
1048*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
1049*4882a593Smuzhiyun [3] = { .scnprintf = SCA_FD, /* group_fd */ },
1050*4882a593Smuzhiyun [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
1051*4882a593Smuzhiyun { .name = "pipe2",
1052*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
1053*4882a593Smuzhiyun { .name = "pkey_alloc",
1054*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
1055*4882a593Smuzhiyun { .name = "pkey_free",
1056*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
1057*4882a593Smuzhiyun { .name = "pkey_mprotect",
1058*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
1059*4882a593Smuzhiyun [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
1060*4882a593Smuzhiyun [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
1061*4882a593Smuzhiyun { .name = "poll", .timeout = true, },
1062*4882a593Smuzhiyun { .name = "ppoll", .timeout = true, },
1063*4882a593Smuzhiyun { .name = "prctl",
1064*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */
1065*4882a593Smuzhiyun .strtoul = STUL_STRARRAY,
1066*4882a593Smuzhiyun .parm = &strarray__prctl_options, },
1067*4882a593Smuzhiyun [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
1068*4882a593Smuzhiyun [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
1069*4882a593Smuzhiyun { .name = "pread", .alias = "pread64", },
1070*4882a593Smuzhiyun { .name = "preadv", .alias = "pread", },
1071*4882a593Smuzhiyun { .name = "prlimit64",
1072*4882a593Smuzhiyun .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
1073*4882a593Smuzhiyun { .name = "pwrite", .alias = "pwrite64", },
1074*4882a593Smuzhiyun { .name = "readlinkat",
1075*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1076*4882a593Smuzhiyun { .name = "recvfrom",
1077*4882a593Smuzhiyun .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1078*4882a593Smuzhiyun { .name = "recvmmsg",
1079*4882a593Smuzhiyun .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1080*4882a593Smuzhiyun { .name = "recvmsg",
1081*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1082*4882a593Smuzhiyun { .name = "renameat",
1083*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* olddirfd */ },
1084*4882a593Smuzhiyun [2] = { .scnprintf = SCA_FDAT, /* newdirfd */ }, }, },
1085*4882a593Smuzhiyun { .name = "renameat2",
1086*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* olddirfd */ },
1087*4882a593Smuzhiyun [2] = { .scnprintf = SCA_FDAT, /* newdirfd */ },
1088*4882a593Smuzhiyun [4] = { .scnprintf = SCA_RENAMEAT2_FLAGS, /* flags */ }, }, },
1089*4882a593Smuzhiyun { .name = "rt_sigaction",
1090*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1091*4882a593Smuzhiyun { .name = "rt_sigprocmask",
1092*4882a593Smuzhiyun .arg = { [0] = STRARRAY(how, sighow), }, },
1093*4882a593Smuzhiyun { .name = "rt_sigqueueinfo",
1094*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1095*4882a593Smuzhiyun { .name = "rt_tgsigqueueinfo",
1096*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1097*4882a593Smuzhiyun { .name = "sched_setscheduler",
1098*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
1099*4882a593Smuzhiyun { .name = "seccomp",
1100*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
1101*4882a593Smuzhiyun [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
1102*4882a593Smuzhiyun { .name = "select", .timeout = true, },
1103*4882a593Smuzhiyun { .name = "sendfile", .alias = "sendfile64", },
1104*4882a593Smuzhiyun { .name = "sendmmsg",
1105*4882a593Smuzhiyun .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1106*4882a593Smuzhiyun { .name = "sendmsg",
1107*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
1108*4882a593Smuzhiyun { .name = "sendto",
1109*4882a593Smuzhiyun .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ },
1110*4882a593Smuzhiyun [4] = { .scnprintf = SCA_SOCKADDR, /* addr */ }, }, },
1111*4882a593Smuzhiyun { .name = "set_tid_address", .errpid = true, },
1112*4882a593Smuzhiyun { .name = "setitimer",
1113*4882a593Smuzhiyun .arg = { [0] = STRARRAY(which, itimers), }, },
1114*4882a593Smuzhiyun { .name = "setrlimit",
1115*4882a593Smuzhiyun .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
1116*4882a593Smuzhiyun { .name = "socket",
1117*4882a593Smuzhiyun .arg = { [0] = STRARRAY(family, socket_families),
1118*4882a593Smuzhiyun [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
1119*4882a593Smuzhiyun [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
1120*4882a593Smuzhiyun { .name = "socketpair",
1121*4882a593Smuzhiyun .arg = { [0] = STRARRAY(family, socket_families),
1122*4882a593Smuzhiyun [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
1123*4882a593Smuzhiyun [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
1124*4882a593Smuzhiyun { .name = "stat", .alias = "newstat", },
1125*4882a593Smuzhiyun { .name = "statx",
1126*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
1127*4882a593Smuzhiyun [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
1128*4882a593Smuzhiyun [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
1129*4882a593Smuzhiyun { .name = "swapoff",
1130*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
1131*4882a593Smuzhiyun { .name = "swapon",
1132*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
1133*4882a593Smuzhiyun { .name = "symlinkat",
1134*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1135*4882a593Smuzhiyun { .name = "sync_file_range",
1136*4882a593Smuzhiyun .arg = { [3] = { .scnprintf = SCA_SYNC_FILE_RANGE_FLAGS, /* flags */ }, }, },
1137*4882a593Smuzhiyun { .name = "tgkill",
1138*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1139*4882a593Smuzhiyun { .name = "tkill",
1140*4882a593Smuzhiyun .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
1141*4882a593Smuzhiyun { .name = "umount2", .alias = "umount",
1142*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FILENAME, /* name */ }, }, },
1143*4882a593Smuzhiyun { .name = "uname", .alias = "newuname", },
1144*4882a593Smuzhiyun { .name = "unlinkat",
1145*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
1146*4882a593Smuzhiyun { .name = "utimensat",
1147*4882a593Smuzhiyun .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
1148*4882a593Smuzhiyun { .name = "wait4", .errpid = true,
1149*4882a593Smuzhiyun .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
1150*4882a593Smuzhiyun { .name = "waitid", .errpid = true,
1151*4882a593Smuzhiyun .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
1152*4882a593Smuzhiyun };
1153*4882a593Smuzhiyun
syscall_fmt__cmp(const void * name,const void * fmtp)1154*4882a593Smuzhiyun static int syscall_fmt__cmp(const void *name, const void *fmtp)
1155*4882a593Smuzhiyun {
1156*4882a593Smuzhiyun const struct syscall_fmt *fmt = fmtp;
1157*4882a593Smuzhiyun return strcmp(name, fmt->name);
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun
__syscall_fmt__find(struct syscall_fmt * fmts,const int nmemb,const char * name)1160*4882a593Smuzhiyun static struct syscall_fmt *__syscall_fmt__find(struct syscall_fmt *fmts, const int nmemb, const char *name)
1161*4882a593Smuzhiyun {
1162*4882a593Smuzhiyun return bsearch(name, fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1163*4882a593Smuzhiyun }
1164*4882a593Smuzhiyun
syscall_fmt__find(const char * name)1165*4882a593Smuzhiyun static struct syscall_fmt *syscall_fmt__find(const char *name)
1166*4882a593Smuzhiyun {
1167*4882a593Smuzhiyun const int nmemb = ARRAY_SIZE(syscall_fmts);
1168*4882a593Smuzhiyun return __syscall_fmt__find(syscall_fmts, nmemb, name);
1169*4882a593Smuzhiyun }
1170*4882a593Smuzhiyun
__syscall_fmt__find_by_alias(struct syscall_fmt * fmts,const int nmemb,const char * alias)1171*4882a593Smuzhiyun static struct syscall_fmt *__syscall_fmt__find_by_alias(struct syscall_fmt *fmts, const int nmemb, const char *alias)
1172*4882a593Smuzhiyun {
1173*4882a593Smuzhiyun int i;
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun for (i = 0; i < nmemb; ++i) {
1176*4882a593Smuzhiyun if (fmts[i].alias && strcmp(fmts[i].alias, alias) == 0)
1177*4882a593Smuzhiyun return &fmts[i];
1178*4882a593Smuzhiyun }
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun return NULL;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun
syscall_fmt__find_by_alias(const char * alias)1183*4882a593Smuzhiyun static struct syscall_fmt *syscall_fmt__find_by_alias(const char *alias)
1184*4882a593Smuzhiyun {
1185*4882a593Smuzhiyun const int nmemb = ARRAY_SIZE(syscall_fmts);
1186*4882a593Smuzhiyun return __syscall_fmt__find_by_alias(syscall_fmts, nmemb, alias);
1187*4882a593Smuzhiyun }
1188*4882a593Smuzhiyun
1189*4882a593Smuzhiyun /*
1190*4882a593Smuzhiyun * is_exit: is this "exit" or "exit_group"?
1191*4882a593Smuzhiyun * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
1192*4882a593Smuzhiyun * args_size: sum of the sizes of the syscall arguments, anything after that is augmented stuff: pathname for openat, etc.
1193*4882a593Smuzhiyun * nonexistent: Just a hole in the syscall table, syscall id not allocated
1194*4882a593Smuzhiyun */
1195*4882a593Smuzhiyun struct syscall {
1196*4882a593Smuzhiyun struct tep_event *tp_format;
1197*4882a593Smuzhiyun int nr_args;
1198*4882a593Smuzhiyun int args_size;
1199*4882a593Smuzhiyun struct {
1200*4882a593Smuzhiyun struct bpf_program *sys_enter,
1201*4882a593Smuzhiyun *sys_exit;
1202*4882a593Smuzhiyun } bpf_prog;
1203*4882a593Smuzhiyun bool is_exit;
1204*4882a593Smuzhiyun bool is_open;
1205*4882a593Smuzhiyun bool nonexistent;
1206*4882a593Smuzhiyun struct tep_format_field *args;
1207*4882a593Smuzhiyun const char *name;
1208*4882a593Smuzhiyun struct syscall_fmt *fmt;
1209*4882a593Smuzhiyun struct syscall_arg_fmt *arg_fmt;
1210*4882a593Smuzhiyun };
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun /*
1213*4882a593Smuzhiyun * Must match what is in the BPF program:
1214*4882a593Smuzhiyun *
1215*4882a593Smuzhiyun * tools/perf/examples/bpf/augmented_raw_syscalls.c
1216*4882a593Smuzhiyun */
1217*4882a593Smuzhiyun struct bpf_map_syscall_entry {
1218*4882a593Smuzhiyun bool enabled;
1219*4882a593Smuzhiyun u16 string_args_len[6];
1220*4882a593Smuzhiyun };
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun /*
1223*4882a593Smuzhiyun * We need to have this 'calculated' boolean because in some cases we really
1224*4882a593Smuzhiyun * don't know what is the duration of a syscall, for instance, when we start
1225*4882a593Smuzhiyun * a session and some threads are waiting for a syscall to finish, say 'poll',
1226*4882a593Smuzhiyun * in which case all we can do is to print "( ? ) for duration and for the
1227*4882a593Smuzhiyun * start timestamp.
1228*4882a593Smuzhiyun */
fprintf_duration(unsigned long t,bool calculated,FILE * fp)1229*4882a593Smuzhiyun static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
1230*4882a593Smuzhiyun {
1231*4882a593Smuzhiyun double duration = (double)t / NSEC_PER_MSEC;
1232*4882a593Smuzhiyun size_t printed = fprintf(fp, "(");
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun if (!calculated)
1235*4882a593Smuzhiyun printed += fprintf(fp, " ");
1236*4882a593Smuzhiyun else if (duration >= 1.0)
1237*4882a593Smuzhiyun printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1238*4882a593Smuzhiyun else if (duration >= 0.01)
1239*4882a593Smuzhiyun printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1240*4882a593Smuzhiyun else
1241*4882a593Smuzhiyun printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
1242*4882a593Smuzhiyun return printed + fprintf(fp, "): ");
1243*4882a593Smuzhiyun }
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun /**
1246*4882a593Smuzhiyun * filename.ptr: The filename char pointer that will be vfs_getname'd
1247*4882a593Smuzhiyun * filename.entry_str_pos: Where to insert the string translated from
1248*4882a593Smuzhiyun * filename.ptr by the vfs_getname tracepoint/kprobe.
1249*4882a593Smuzhiyun * ret_scnprintf: syscall args may set this to a different syscall return
1250*4882a593Smuzhiyun * formatter, for instance, fcntl may return fds, file flags, etc.
1251*4882a593Smuzhiyun */
1252*4882a593Smuzhiyun struct thread_trace {
1253*4882a593Smuzhiyun u64 entry_time;
1254*4882a593Smuzhiyun bool entry_pending;
1255*4882a593Smuzhiyun unsigned long nr_events;
1256*4882a593Smuzhiyun unsigned long pfmaj, pfmin;
1257*4882a593Smuzhiyun char *entry_str;
1258*4882a593Smuzhiyun double runtime_ms;
1259*4882a593Smuzhiyun size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1260*4882a593Smuzhiyun struct {
1261*4882a593Smuzhiyun unsigned long ptr;
1262*4882a593Smuzhiyun short int entry_str_pos;
1263*4882a593Smuzhiyun bool pending_open;
1264*4882a593Smuzhiyun unsigned int namelen;
1265*4882a593Smuzhiyun char *name;
1266*4882a593Smuzhiyun } filename;
1267*4882a593Smuzhiyun struct {
1268*4882a593Smuzhiyun int max;
1269*4882a593Smuzhiyun struct file *table;
1270*4882a593Smuzhiyun } files;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun struct intlist *syscall_stats;
1273*4882a593Smuzhiyun };
1274*4882a593Smuzhiyun
thread_trace__new(void)1275*4882a593Smuzhiyun static struct thread_trace *thread_trace__new(void)
1276*4882a593Smuzhiyun {
1277*4882a593Smuzhiyun struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1278*4882a593Smuzhiyun
1279*4882a593Smuzhiyun if (ttrace) {
1280*4882a593Smuzhiyun ttrace->files.max = -1;
1281*4882a593Smuzhiyun ttrace->syscall_stats = intlist__new(NULL);
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun return ttrace;
1285*4882a593Smuzhiyun }
1286*4882a593Smuzhiyun
thread__trace(struct thread * thread,FILE * fp)1287*4882a593Smuzhiyun static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
1288*4882a593Smuzhiyun {
1289*4882a593Smuzhiyun struct thread_trace *ttrace;
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun if (thread == NULL)
1292*4882a593Smuzhiyun goto fail;
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun if (thread__priv(thread) == NULL)
1295*4882a593Smuzhiyun thread__set_priv(thread, thread_trace__new());
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun if (thread__priv(thread) == NULL)
1298*4882a593Smuzhiyun goto fail;
1299*4882a593Smuzhiyun
1300*4882a593Smuzhiyun ttrace = thread__priv(thread);
1301*4882a593Smuzhiyun ++ttrace->nr_events;
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun return ttrace;
1304*4882a593Smuzhiyun fail:
1305*4882a593Smuzhiyun color_fprintf(fp, PERF_COLOR_RED,
1306*4882a593Smuzhiyun "WARNING: not enough memory, dropping samples!\n");
1307*4882a593Smuzhiyun return NULL;
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
1310*4882a593Smuzhiyun
syscall_arg__set_ret_scnprintf(struct syscall_arg * arg,size_t (* ret_scnprintf)(char * bf,size_t size,struct syscall_arg * arg))1311*4882a593Smuzhiyun void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
1312*4882a593Smuzhiyun size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
1313*4882a593Smuzhiyun {
1314*4882a593Smuzhiyun struct thread_trace *ttrace = thread__priv(arg->thread);
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun ttrace->ret_scnprintf = ret_scnprintf;
1317*4882a593Smuzhiyun }
1318*4882a593Smuzhiyun
1319*4882a593Smuzhiyun #define TRACE_PFMAJ (1 << 0)
1320*4882a593Smuzhiyun #define TRACE_PFMIN (1 << 1)
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun static const size_t trace__entry_str_size = 2048;
1323*4882a593Smuzhiyun
thread_trace__files_entry(struct thread_trace * ttrace,int fd)1324*4882a593Smuzhiyun static struct file *thread_trace__files_entry(struct thread_trace *ttrace, int fd)
1325*4882a593Smuzhiyun {
1326*4882a593Smuzhiyun if (fd < 0)
1327*4882a593Smuzhiyun return NULL;
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun if (fd > ttrace->files.max) {
1330*4882a593Smuzhiyun struct file *nfiles = realloc(ttrace->files.table, (fd + 1) * sizeof(struct file));
1331*4882a593Smuzhiyun
1332*4882a593Smuzhiyun if (nfiles == NULL)
1333*4882a593Smuzhiyun return NULL;
1334*4882a593Smuzhiyun
1335*4882a593Smuzhiyun if (ttrace->files.max != -1) {
1336*4882a593Smuzhiyun memset(nfiles + ttrace->files.max + 1, 0,
1337*4882a593Smuzhiyun (fd - ttrace->files.max) * sizeof(struct file));
1338*4882a593Smuzhiyun } else {
1339*4882a593Smuzhiyun memset(nfiles, 0, (fd + 1) * sizeof(struct file));
1340*4882a593Smuzhiyun }
1341*4882a593Smuzhiyun
1342*4882a593Smuzhiyun ttrace->files.table = nfiles;
1343*4882a593Smuzhiyun ttrace->files.max = fd;
1344*4882a593Smuzhiyun }
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun return ttrace->files.table + fd;
1347*4882a593Smuzhiyun }
1348*4882a593Smuzhiyun
thread__files_entry(struct thread * thread,int fd)1349*4882a593Smuzhiyun struct file *thread__files_entry(struct thread *thread, int fd)
1350*4882a593Smuzhiyun {
1351*4882a593Smuzhiyun return thread_trace__files_entry(thread__priv(thread), fd);
1352*4882a593Smuzhiyun }
1353*4882a593Smuzhiyun
trace__set_fd_pathname(struct thread * thread,int fd,const char * pathname)1354*4882a593Smuzhiyun static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
1355*4882a593Smuzhiyun {
1356*4882a593Smuzhiyun struct thread_trace *ttrace = thread__priv(thread);
1357*4882a593Smuzhiyun struct file *file = thread_trace__files_entry(ttrace, fd);
1358*4882a593Smuzhiyun
1359*4882a593Smuzhiyun if (file != NULL) {
1360*4882a593Smuzhiyun struct stat st;
1361*4882a593Smuzhiyun if (stat(pathname, &st) == 0)
1362*4882a593Smuzhiyun file->dev_maj = major(st.st_rdev);
1363*4882a593Smuzhiyun file->pathname = strdup(pathname);
1364*4882a593Smuzhiyun if (file->pathname)
1365*4882a593Smuzhiyun return 0;
1366*4882a593Smuzhiyun }
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun return -1;
1369*4882a593Smuzhiyun }
1370*4882a593Smuzhiyun
thread__read_fd_path(struct thread * thread,int fd)1371*4882a593Smuzhiyun static int thread__read_fd_path(struct thread *thread, int fd)
1372*4882a593Smuzhiyun {
1373*4882a593Smuzhiyun char linkname[PATH_MAX], pathname[PATH_MAX];
1374*4882a593Smuzhiyun struct stat st;
1375*4882a593Smuzhiyun int ret;
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun if (thread->pid_ == thread->tid) {
1378*4882a593Smuzhiyun scnprintf(linkname, sizeof(linkname),
1379*4882a593Smuzhiyun "/proc/%d/fd/%d", thread->pid_, fd);
1380*4882a593Smuzhiyun } else {
1381*4882a593Smuzhiyun scnprintf(linkname, sizeof(linkname),
1382*4882a593Smuzhiyun "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1383*4882a593Smuzhiyun }
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1386*4882a593Smuzhiyun return -1;
1387*4882a593Smuzhiyun
1388*4882a593Smuzhiyun ret = readlink(linkname, pathname, sizeof(pathname));
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun if (ret < 0 || ret > st.st_size)
1391*4882a593Smuzhiyun return -1;
1392*4882a593Smuzhiyun
1393*4882a593Smuzhiyun pathname[ret] = '\0';
1394*4882a593Smuzhiyun return trace__set_fd_pathname(thread, fd, pathname);
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun
thread__fd_path(struct thread * thread,int fd,struct trace * trace)1397*4882a593Smuzhiyun static const char *thread__fd_path(struct thread *thread, int fd,
1398*4882a593Smuzhiyun struct trace *trace)
1399*4882a593Smuzhiyun {
1400*4882a593Smuzhiyun struct thread_trace *ttrace = thread__priv(thread);
1401*4882a593Smuzhiyun
1402*4882a593Smuzhiyun if (ttrace == NULL || trace->fd_path_disabled)
1403*4882a593Smuzhiyun return NULL;
1404*4882a593Smuzhiyun
1405*4882a593Smuzhiyun if (fd < 0)
1406*4882a593Smuzhiyun return NULL;
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun if ((fd > ttrace->files.max || ttrace->files.table[fd].pathname == NULL)) {
1409*4882a593Smuzhiyun if (!trace->live)
1410*4882a593Smuzhiyun return NULL;
1411*4882a593Smuzhiyun ++trace->stats.proc_getname;
1412*4882a593Smuzhiyun if (thread__read_fd_path(thread, fd))
1413*4882a593Smuzhiyun return NULL;
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun
1416*4882a593Smuzhiyun return ttrace->files.table[fd].pathname;
1417*4882a593Smuzhiyun }
1418*4882a593Smuzhiyun
syscall_arg__scnprintf_fd(char * bf,size_t size,struct syscall_arg * arg)1419*4882a593Smuzhiyun size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
1420*4882a593Smuzhiyun {
1421*4882a593Smuzhiyun int fd = arg->val;
1422*4882a593Smuzhiyun size_t printed = scnprintf(bf, size, "%d", fd);
1423*4882a593Smuzhiyun const char *path = thread__fd_path(arg->thread, fd, arg->trace);
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun if (path)
1426*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1427*4882a593Smuzhiyun
1428*4882a593Smuzhiyun return printed;
1429*4882a593Smuzhiyun }
1430*4882a593Smuzhiyun
pid__scnprintf_fd(struct trace * trace,pid_t pid,int fd,char * bf,size_t size)1431*4882a593Smuzhiyun size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1432*4882a593Smuzhiyun {
1433*4882a593Smuzhiyun size_t printed = scnprintf(bf, size, "%d", fd);
1434*4882a593Smuzhiyun struct thread *thread = machine__find_thread(trace->host, pid, pid);
1435*4882a593Smuzhiyun
1436*4882a593Smuzhiyun if (thread) {
1437*4882a593Smuzhiyun const char *path = thread__fd_path(thread, fd, trace);
1438*4882a593Smuzhiyun
1439*4882a593Smuzhiyun if (path)
1440*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun thread__put(thread);
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun return printed;
1446*4882a593Smuzhiyun }
1447*4882a593Smuzhiyun
syscall_arg__scnprintf_close_fd(char * bf,size_t size,struct syscall_arg * arg)1448*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1449*4882a593Smuzhiyun struct syscall_arg *arg)
1450*4882a593Smuzhiyun {
1451*4882a593Smuzhiyun int fd = arg->val;
1452*4882a593Smuzhiyun size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1453*4882a593Smuzhiyun struct thread_trace *ttrace = thread__priv(arg->thread);
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun if (ttrace && fd >= 0 && fd <= ttrace->files.max)
1456*4882a593Smuzhiyun zfree(&ttrace->files.table[fd].pathname);
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun return printed;
1459*4882a593Smuzhiyun }
1460*4882a593Smuzhiyun
thread__set_filename_pos(struct thread * thread,const char * bf,unsigned long ptr)1461*4882a593Smuzhiyun static void thread__set_filename_pos(struct thread *thread, const char *bf,
1462*4882a593Smuzhiyun unsigned long ptr)
1463*4882a593Smuzhiyun {
1464*4882a593Smuzhiyun struct thread_trace *ttrace = thread__priv(thread);
1465*4882a593Smuzhiyun
1466*4882a593Smuzhiyun ttrace->filename.ptr = ptr;
1467*4882a593Smuzhiyun ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1468*4882a593Smuzhiyun }
1469*4882a593Smuzhiyun
syscall_arg__scnprintf_augmented_string(struct syscall_arg * arg,char * bf,size_t size)1470*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_augmented_string(struct syscall_arg *arg, char *bf, size_t size)
1471*4882a593Smuzhiyun {
1472*4882a593Smuzhiyun struct augmented_arg *augmented_arg = arg->augmented.args;
1473*4882a593Smuzhiyun size_t printed = scnprintf(bf, size, "\"%.*s\"", augmented_arg->size, augmented_arg->value);
1474*4882a593Smuzhiyun /*
1475*4882a593Smuzhiyun * So that the next arg with a payload can consume its augmented arg, i.e. for rename* syscalls
1476*4882a593Smuzhiyun * we would have two strings, each prefixed by its size.
1477*4882a593Smuzhiyun */
1478*4882a593Smuzhiyun int consumed = sizeof(*augmented_arg) + augmented_arg->size;
1479*4882a593Smuzhiyun
1480*4882a593Smuzhiyun arg->augmented.args = ((void *)arg->augmented.args) + consumed;
1481*4882a593Smuzhiyun arg->augmented.size -= consumed;
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun return printed;
1484*4882a593Smuzhiyun }
1485*4882a593Smuzhiyun
syscall_arg__scnprintf_filename(char * bf,size_t size,struct syscall_arg * arg)1486*4882a593Smuzhiyun static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1487*4882a593Smuzhiyun struct syscall_arg *arg)
1488*4882a593Smuzhiyun {
1489*4882a593Smuzhiyun unsigned long ptr = arg->val;
1490*4882a593Smuzhiyun
1491*4882a593Smuzhiyun if (arg->augmented.args)
1492*4882a593Smuzhiyun return syscall_arg__scnprintf_augmented_string(arg, bf, size);
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun if (!arg->trace->vfs_getname)
1495*4882a593Smuzhiyun return scnprintf(bf, size, "%#x", ptr);
1496*4882a593Smuzhiyun
1497*4882a593Smuzhiyun thread__set_filename_pos(arg->thread, bf, ptr);
1498*4882a593Smuzhiyun return 0;
1499*4882a593Smuzhiyun }
1500*4882a593Smuzhiyun
trace__filter_duration(struct trace * trace,double t)1501*4882a593Smuzhiyun static bool trace__filter_duration(struct trace *trace, double t)
1502*4882a593Smuzhiyun {
1503*4882a593Smuzhiyun return t < (trace->duration_filter * NSEC_PER_MSEC);
1504*4882a593Smuzhiyun }
1505*4882a593Smuzhiyun
__trace__fprintf_tstamp(struct trace * trace,u64 tstamp,FILE * fp)1506*4882a593Smuzhiyun static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1507*4882a593Smuzhiyun {
1508*4882a593Smuzhiyun double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1509*4882a593Smuzhiyun
1510*4882a593Smuzhiyun return fprintf(fp, "%10.3f ", ts);
1511*4882a593Smuzhiyun }
1512*4882a593Smuzhiyun
1513*4882a593Smuzhiyun /*
1514*4882a593Smuzhiyun * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1515*4882a593Smuzhiyun * using ttrace->entry_time for a thread that receives a sys_exit without
1516*4882a593Smuzhiyun * first having received a sys_enter ("poll" issued before tracing session
1517*4882a593Smuzhiyun * starts, lost sys_enter exit due to ring buffer overflow).
1518*4882a593Smuzhiyun */
trace__fprintf_tstamp(struct trace * trace,u64 tstamp,FILE * fp)1519*4882a593Smuzhiyun static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1520*4882a593Smuzhiyun {
1521*4882a593Smuzhiyun if (tstamp > 0)
1522*4882a593Smuzhiyun return __trace__fprintf_tstamp(trace, tstamp, fp);
1523*4882a593Smuzhiyun
1524*4882a593Smuzhiyun return fprintf(fp, " ? ");
1525*4882a593Smuzhiyun }
1526*4882a593Smuzhiyun
1527*4882a593Smuzhiyun static bool done = false;
1528*4882a593Smuzhiyun static bool interrupted = false;
1529*4882a593Smuzhiyun
sig_handler(int sig)1530*4882a593Smuzhiyun static void sig_handler(int sig)
1531*4882a593Smuzhiyun {
1532*4882a593Smuzhiyun done = true;
1533*4882a593Smuzhiyun interrupted = sig == SIGINT;
1534*4882a593Smuzhiyun }
1535*4882a593Smuzhiyun
trace__fprintf_comm_tid(struct trace * trace,struct thread * thread,FILE * fp)1536*4882a593Smuzhiyun static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread, FILE *fp)
1537*4882a593Smuzhiyun {
1538*4882a593Smuzhiyun size_t printed = 0;
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun if (trace->multiple_threads) {
1541*4882a593Smuzhiyun if (trace->show_comm)
1542*4882a593Smuzhiyun printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
1543*4882a593Smuzhiyun printed += fprintf(fp, "%d ", thread->tid);
1544*4882a593Smuzhiyun }
1545*4882a593Smuzhiyun
1546*4882a593Smuzhiyun return printed;
1547*4882a593Smuzhiyun }
1548*4882a593Smuzhiyun
trace__fprintf_entry_head(struct trace * trace,struct thread * thread,u64 duration,bool duration_calculated,u64 tstamp,FILE * fp)1549*4882a593Smuzhiyun static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
1550*4882a593Smuzhiyun u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
1551*4882a593Smuzhiyun {
1552*4882a593Smuzhiyun size_t printed = 0;
1553*4882a593Smuzhiyun
1554*4882a593Smuzhiyun if (trace->show_tstamp)
1555*4882a593Smuzhiyun printed = trace__fprintf_tstamp(trace, tstamp, fp);
1556*4882a593Smuzhiyun if (trace->show_duration)
1557*4882a593Smuzhiyun printed += fprintf_duration(duration, duration_calculated, fp);
1558*4882a593Smuzhiyun return printed + trace__fprintf_comm_tid(trace, thread, fp);
1559*4882a593Smuzhiyun }
1560*4882a593Smuzhiyun
trace__process_event(struct trace * trace,struct machine * machine,union perf_event * event,struct perf_sample * sample)1561*4882a593Smuzhiyun static int trace__process_event(struct trace *trace, struct machine *machine,
1562*4882a593Smuzhiyun union perf_event *event, struct perf_sample *sample)
1563*4882a593Smuzhiyun {
1564*4882a593Smuzhiyun int ret = 0;
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun switch (event->header.type) {
1567*4882a593Smuzhiyun case PERF_RECORD_LOST:
1568*4882a593Smuzhiyun color_fprintf(trace->output, PERF_COLOR_RED,
1569*4882a593Smuzhiyun "LOST %" PRIu64 " events!\n", event->lost.lost);
1570*4882a593Smuzhiyun ret = machine__process_lost_event(machine, event, sample);
1571*4882a593Smuzhiyun break;
1572*4882a593Smuzhiyun default:
1573*4882a593Smuzhiyun ret = machine__process_event(machine, event, sample);
1574*4882a593Smuzhiyun break;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun
1577*4882a593Smuzhiyun return ret;
1578*4882a593Smuzhiyun }
1579*4882a593Smuzhiyun
trace__tool_process(struct perf_tool * tool,union perf_event * event,struct perf_sample * sample,struct machine * machine)1580*4882a593Smuzhiyun static int trace__tool_process(struct perf_tool *tool,
1581*4882a593Smuzhiyun union perf_event *event,
1582*4882a593Smuzhiyun struct perf_sample *sample,
1583*4882a593Smuzhiyun struct machine *machine)
1584*4882a593Smuzhiyun {
1585*4882a593Smuzhiyun struct trace *trace = container_of(tool, struct trace, tool);
1586*4882a593Smuzhiyun return trace__process_event(trace, machine, event, sample);
1587*4882a593Smuzhiyun }
1588*4882a593Smuzhiyun
trace__machine__resolve_kernel_addr(void * vmachine,unsigned long long * addrp,char ** modp)1589*4882a593Smuzhiyun static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1590*4882a593Smuzhiyun {
1591*4882a593Smuzhiyun struct machine *machine = vmachine;
1592*4882a593Smuzhiyun
1593*4882a593Smuzhiyun if (machine->kptr_restrict_warned)
1594*4882a593Smuzhiyun return NULL;
1595*4882a593Smuzhiyun
1596*4882a593Smuzhiyun if (symbol_conf.kptr_restrict) {
1597*4882a593Smuzhiyun pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1598*4882a593Smuzhiyun "Check /proc/sys/kernel/kptr_restrict and /proc/sys/kernel/perf_event_paranoid.\n\n"
1599*4882a593Smuzhiyun "Kernel samples will not be resolved.\n");
1600*4882a593Smuzhiyun machine->kptr_restrict_warned = true;
1601*4882a593Smuzhiyun return NULL;
1602*4882a593Smuzhiyun }
1603*4882a593Smuzhiyun
1604*4882a593Smuzhiyun return machine__resolve_kernel_addr(vmachine, addrp, modp);
1605*4882a593Smuzhiyun }
1606*4882a593Smuzhiyun
trace__symbols_init(struct trace * trace,struct evlist * evlist)1607*4882a593Smuzhiyun static int trace__symbols_init(struct trace *trace, struct evlist *evlist)
1608*4882a593Smuzhiyun {
1609*4882a593Smuzhiyun int err = symbol__init(NULL);
1610*4882a593Smuzhiyun
1611*4882a593Smuzhiyun if (err)
1612*4882a593Smuzhiyun return err;
1613*4882a593Smuzhiyun
1614*4882a593Smuzhiyun trace->host = machine__new_host();
1615*4882a593Smuzhiyun if (trace->host == NULL)
1616*4882a593Smuzhiyun return -ENOMEM;
1617*4882a593Smuzhiyun
1618*4882a593Smuzhiyun err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1619*4882a593Smuzhiyun if (err < 0)
1620*4882a593Smuzhiyun goto out;
1621*4882a593Smuzhiyun
1622*4882a593Smuzhiyun err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
1623*4882a593Smuzhiyun evlist->core.threads, trace__tool_process, false,
1624*4882a593Smuzhiyun 1);
1625*4882a593Smuzhiyun out:
1626*4882a593Smuzhiyun if (err)
1627*4882a593Smuzhiyun symbol__exit();
1628*4882a593Smuzhiyun
1629*4882a593Smuzhiyun return err;
1630*4882a593Smuzhiyun }
1631*4882a593Smuzhiyun
trace__symbols__exit(struct trace * trace)1632*4882a593Smuzhiyun static void trace__symbols__exit(struct trace *trace)
1633*4882a593Smuzhiyun {
1634*4882a593Smuzhiyun machine__exit(trace->host);
1635*4882a593Smuzhiyun trace->host = NULL;
1636*4882a593Smuzhiyun
1637*4882a593Smuzhiyun symbol__exit();
1638*4882a593Smuzhiyun }
1639*4882a593Smuzhiyun
syscall__alloc_arg_fmts(struct syscall * sc,int nr_args)1640*4882a593Smuzhiyun static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1641*4882a593Smuzhiyun {
1642*4882a593Smuzhiyun int idx;
1643*4882a593Smuzhiyun
1644*4882a593Smuzhiyun if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1645*4882a593Smuzhiyun nr_args = sc->fmt->nr_args;
1646*4882a593Smuzhiyun
1647*4882a593Smuzhiyun sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1648*4882a593Smuzhiyun if (sc->arg_fmt == NULL)
1649*4882a593Smuzhiyun return -1;
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun for (idx = 0; idx < nr_args; ++idx) {
1652*4882a593Smuzhiyun if (sc->fmt)
1653*4882a593Smuzhiyun sc->arg_fmt[idx] = sc->fmt->arg[idx];
1654*4882a593Smuzhiyun }
1655*4882a593Smuzhiyun
1656*4882a593Smuzhiyun sc->nr_args = nr_args;
1657*4882a593Smuzhiyun return 0;
1658*4882a593Smuzhiyun }
1659*4882a593Smuzhiyun
1660*4882a593Smuzhiyun static struct syscall_arg_fmt syscall_arg_fmts__by_name[] = {
1661*4882a593Smuzhiyun { .name = "msr", .scnprintf = SCA_X86_MSR, .strtoul = STUL_X86_MSR, },
1662*4882a593Smuzhiyun { .name = "vector", .scnprintf = SCA_X86_IRQ_VECTORS, .strtoul = STUL_X86_IRQ_VECTORS, },
1663*4882a593Smuzhiyun };
1664*4882a593Smuzhiyun
syscall_arg_fmt__cmp(const void * name,const void * fmtp)1665*4882a593Smuzhiyun static int syscall_arg_fmt__cmp(const void *name, const void *fmtp)
1666*4882a593Smuzhiyun {
1667*4882a593Smuzhiyun const struct syscall_arg_fmt *fmt = fmtp;
1668*4882a593Smuzhiyun return strcmp(name, fmt->name);
1669*4882a593Smuzhiyun }
1670*4882a593Smuzhiyun
1671*4882a593Smuzhiyun static struct syscall_arg_fmt *
__syscall_arg_fmt__find_by_name(struct syscall_arg_fmt * fmts,const int nmemb,const char * name)1672*4882a593Smuzhiyun __syscall_arg_fmt__find_by_name(struct syscall_arg_fmt *fmts, const int nmemb, const char *name)
1673*4882a593Smuzhiyun {
1674*4882a593Smuzhiyun return bsearch(name, fmts, nmemb, sizeof(struct syscall_arg_fmt), syscall_arg_fmt__cmp);
1675*4882a593Smuzhiyun }
1676*4882a593Smuzhiyun
syscall_arg_fmt__find_by_name(const char * name)1677*4882a593Smuzhiyun static struct syscall_arg_fmt *syscall_arg_fmt__find_by_name(const char *name)
1678*4882a593Smuzhiyun {
1679*4882a593Smuzhiyun const int nmemb = ARRAY_SIZE(syscall_arg_fmts__by_name);
1680*4882a593Smuzhiyun return __syscall_arg_fmt__find_by_name(syscall_arg_fmts__by_name, nmemb, name);
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun static struct tep_format_field *
syscall_arg_fmt__init_array(struct syscall_arg_fmt * arg,struct tep_format_field * field)1684*4882a593Smuzhiyun syscall_arg_fmt__init_array(struct syscall_arg_fmt *arg, struct tep_format_field *field)
1685*4882a593Smuzhiyun {
1686*4882a593Smuzhiyun struct tep_format_field *last_field = NULL;
1687*4882a593Smuzhiyun int len;
1688*4882a593Smuzhiyun
1689*4882a593Smuzhiyun for (; field; field = field->next, ++arg) {
1690*4882a593Smuzhiyun last_field = field;
1691*4882a593Smuzhiyun
1692*4882a593Smuzhiyun if (arg->scnprintf)
1693*4882a593Smuzhiyun continue;
1694*4882a593Smuzhiyun
1695*4882a593Smuzhiyun len = strlen(field->name);
1696*4882a593Smuzhiyun
1697*4882a593Smuzhiyun if (strcmp(field->type, "const char *") == 0 &&
1698*4882a593Smuzhiyun ((len >= 4 && strcmp(field->name + len - 4, "name") == 0) ||
1699*4882a593Smuzhiyun strstr(field->name, "path") != NULL))
1700*4882a593Smuzhiyun arg->scnprintf = SCA_FILENAME;
1701*4882a593Smuzhiyun else if ((field->flags & TEP_FIELD_IS_POINTER) || strstr(field->name, "addr"))
1702*4882a593Smuzhiyun arg->scnprintf = SCA_PTR;
1703*4882a593Smuzhiyun else if (strcmp(field->type, "pid_t") == 0)
1704*4882a593Smuzhiyun arg->scnprintf = SCA_PID;
1705*4882a593Smuzhiyun else if (strcmp(field->type, "umode_t") == 0)
1706*4882a593Smuzhiyun arg->scnprintf = SCA_MODE_T;
1707*4882a593Smuzhiyun else if ((field->flags & TEP_FIELD_IS_ARRAY) && strstr(field->type, "char")) {
1708*4882a593Smuzhiyun arg->scnprintf = SCA_CHAR_ARRAY;
1709*4882a593Smuzhiyun arg->nr_entries = field->arraylen;
1710*4882a593Smuzhiyun } else if ((strcmp(field->type, "int") == 0 ||
1711*4882a593Smuzhiyun strcmp(field->type, "unsigned int") == 0 ||
1712*4882a593Smuzhiyun strcmp(field->type, "long") == 0) &&
1713*4882a593Smuzhiyun len >= 2 && strcmp(field->name + len - 2, "fd") == 0) {
1714*4882a593Smuzhiyun /*
1715*4882a593Smuzhiyun * /sys/kernel/tracing/events/syscalls/sys_enter*
1716*4882a593Smuzhiyun * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1717*4882a593Smuzhiyun * 65 int
1718*4882a593Smuzhiyun * 23 unsigned int
1719*4882a593Smuzhiyun * 7 unsigned long
1720*4882a593Smuzhiyun */
1721*4882a593Smuzhiyun arg->scnprintf = SCA_FD;
1722*4882a593Smuzhiyun } else {
1723*4882a593Smuzhiyun struct syscall_arg_fmt *fmt = syscall_arg_fmt__find_by_name(field->name);
1724*4882a593Smuzhiyun
1725*4882a593Smuzhiyun if (fmt) {
1726*4882a593Smuzhiyun arg->scnprintf = fmt->scnprintf;
1727*4882a593Smuzhiyun arg->strtoul = fmt->strtoul;
1728*4882a593Smuzhiyun }
1729*4882a593Smuzhiyun }
1730*4882a593Smuzhiyun }
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun return last_field;
1733*4882a593Smuzhiyun }
1734*4882a593Smuzhiyun
syscall__set_arg_fmts(struct syscall * sc)1735*4882a593Smuzhiyun static int syscall__set_arg_fmts(struct syscall *sc)
1736*4882a593Smuzhiyun {
1737*4882a593Smuzhiyun struct tep_format_field *last_field = syscall_arg_fmt__init_array(sc->arg_fmt, sc->args);
1738*4882a593Smuzhiyun
1739*4882a593Smuzhiyun if (last_field)
1740*4882a593Smuzhiyun sc->args_size = last_field->offset + last_field->size;
1741*4882a593Smuzhiyun
1742*4882a593Smuzhiyun return 0;
1743*4882a593Smuzhiyun }
1744*4882a593Smuzhiyun
trace__read_syscall_info(struct trace * trace,int id)1745*4882a593Smuzhiyun static int trace__read_syscall_info(struct trace *trace, int id)
1746*4882a593Smuzhiyun {
1747*4882a593Smuzhiyun char tp_name[128];
1748*4882a593Smuzhiyun struct syscall *sc;
1749*4882a593Smuzhiyun const char *name = syscalltbl__name(trace->sctbl, id);
1750*4882a593Smuzhiyun
1751*4882a593Smuzhiyun #ifdef HAVE_SYSCALL_TABLE_SUPPORT
1752*4882a593Smuzhiyun if (trace->syscalls.table == NULL) {
1753*4882a593Smuzhiyun trace->syscalls.table = calloc(trace->sctbl->syscalls.max_id + 1, sizeof(*sc));
1754*4882a593Smuzhiyun if (trace->syscalls.table == NULL)
1755*4882a593Smuzhiyun return -ENOMEM;
1756*4882a593Smuzhiyun }
1757*4882a593Smuzhiyun #else
1758*4882a593Smuzhiyun if (id > trace->sctbl->syscalls.max_id || (id == 0 && trace->syscalls.table == NULL)) {
1759*4882a593Smuzhiyun // When using libaudit we don't know beforehand what is the max syscall id
1760*4882a593Smuzhiyun struct syscall *table = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1761*4882a593Smuzhiyun
1762*4882a593Smuzhiyun if (table == NULL)
1763*4882a593Smuzhiyun return -ENOMEM;
1764*4882a593Smuzhiyun
1765*4882a593Smuzhiyun // Need to memset from offset 0 and +1 members if brand new
1766*4882a593Smuzhiyun if (trace->syscalls.table == NULL)
1767*4882a593Smuzhiyun memset(table, 0, (id + 1) * sizeof(*sc));
1768*4882a593Smuzhiyun else
1769*4882a593Smuzhiyun memset(table + trace->sctbl->syscalls.max_id + 1, 0, (id - trace->sctbl->syscalls.max_id) * sizeof(*sc));
1770*4882a593Smuzhiyun
1771*4882a593Smuzhiyun trace->syscalls.table = table;
1772*4882a593Smuzhiyun trace->sctbl->syscalls.max_id = id;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun #endif
1775*4882a593Smuzhiyun sc = trace->syscalls.table + id;
1776*4882a593Smuzhiyun if (sc->nonexistent)
1777*4882a593Smuzhiyun return 0;
1778*4882a593Smuzhiyun
1779*4882a593Smuzhiyun if (name == NULL) {
1780*4882a593Smuzhiyun sc->nonexistent = true;
1781*4882a593Smuzhiyun return 0;
1782*4882a593Smuzhiyun }
1783*4882a593Smuzhiyun
1784*4882a593Smuzhiyun sc->name = name;
1785*4882a593Smuzhiyun sc->fmt = syscall_fmt__find(sc->name);
1786*4882a593Smuzhiyun
1787*4882a593Smuzhiyun snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1788*4882a593Smuzhiyun sc->tp_format = trace_event__tp_format("syscalls", tp_name);
1789*4882a593Smuzhiyun
1790*4882a593Smuzhiyun if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
1791*4882a593Smuzhiyun snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1792*4882a593Smuzhiyun sc->tp_format = trace_event__tp_format("syscalls", tp_name);
1793*4882a593Smuzhiyun }
1794*4882a593Smuzhiyun
1795*4882a593Smuzhiyun if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1796*4882a593Smuzhiyun return -ENOMEM;
1797*4882a593Smuzhiyun
1798*4882a593Smuzhiyun if (IS_ERR(sc->tp_format))
1799*4882a593Smuzhiyun return PTR_ERR(sc->tp_format);
1800*4882a593Smuzhiyun
1801*4882a593Smuzhiyun sc->args = sc->tp_format->format.fields;
1802*4882a593Smuzhiyun /*
1803*4882a593Smuzhiyun * We need to check and discard the first variable '__syscall_nr'
1804*4882a593Smuzhiyun * or 'nr' that mean the syscall number. It is needless here.
1805*4882a593Smuzhiyun * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1806*4882a593Smuzhiyun */
1807*4882a593Smuzhiyun if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
1808*4882a593Smuzhiyun sc->args = sc->args->next;
1809*4882a593Smuzhiyun --sc->nr_args;
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun
1812*4882a593Smuzhiyun sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1813*4882a593Smuzhiyun sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun return syscall__set_arg_fmts(sc);
1816*4882a593Smuzhiyun }
1817*4882a593Smuzhiyun
evsel__init_tp_arg_scnprintf(struct evsel * evsel)1818*4882a593Smuzhiyun static int evsel__init_tp_arg_scnprintf(struct evsel *evsel)
1819*4882a593Smuzhiyun {
1820*4882a593Smuzhiyun struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
1821*4882a593Smuzhiyun
1822*4882a593Smuzhiyun if (fmt != NULL) {
1823*4882a593Smuzhiyun syscall_arg_fmt__init_array(fmt, evsel->tp_format->format.fields);
1824*4882a593Smuzhiyun return 0;
1825*4882a593Smuzhiyun }
1826*4882a593Smuzhiyun
1827*4882a593Smuzhiyun return -ENOMEM;
1828*4882a593Smuzhiyun }
1829*4882a593Smuzhiyun
intcmp(const void * a,const void * b)1830*4882a593Smuzhiyun static int intcmp(const void *a, const void *b)
1831*4882a593Smuzhiyun {
1832*4882a593Smuzhiyun const int *one = a, *another = b;
1833*4882a593Smuzhiyun
1834*4882a593Smuzhiyun return *one - *another;
1835*4882a593Smuzhiyun }
1836*4882a593Smuzhiyun
trace__validate_ev_qualifier(struct trace * trace)1837*4882a593Smuzhiyun static int trace__validate_ev_qualifier(struct trace *trace)
1838*4882a593Smuzhiyun {
1839*4882a593Smuzhiyun int err = 0;
1840*4882a593Smuzhiyun bool printed_invalid_prefix = false;
1841*4882a593Smuzhiyun struct str_node *pos;
1842*4882a593Smuzhiyun size_t nr_used = 0, nr_allocated = strlist__nr_entries(trace->ev_qualifier);
1843*4882a593Smuzhiyun
1844*4882a593Smuzhiyun trace->ev_qualifier_ids.entries = malloc(nr_allocated *
1845*4882a593Smuzhiyun sizeof(trace->ev_qualifier_ids.entries[0]));
1846*4882a593Smuzhiyun
1847*4882a593Smuzhiyun if (trace->ev_qualifier_ids.entries == NULL) {
1848*4882a593Smuzhiyun fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1849*4882a593Smuzhiyun trace->output);
1850*4882a593Smuzhiyun err = -EINVAL;
1851*4882a593Smuzhiyun goto out;
1852*4882a593Smuzhiyun }
1853*4882a593Smuzhiyun
1854*4882a593Smuzhiyun strlist__for_each_entry(pos, trace->ev_qualifier) {
1855*4882a593Smuzhiyun const char *sc = pos->s;
1856*4882a593Smuzhiyun int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
1857*4882a593Smuzhiyun
1858*4882a593Smuzhiyun if (id < 0) {
1859*4882a593Smuzhiyun id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1860*4882a593Smuzhiyun if (id >= 0)
1861*4882a593Smuzhiyun goto matches;
1862*4882a593Smuzhiyun
1863*4882a593Smuzhiyun if (!printed_invalid_prefix) {
1864*4882a593Smuzhiyun pr_debug("Skipping unknown syscalls: ");
1865*4882a593Smuzhiyun printed_invalid_prefix = true;
1866*4882a593Smuzhiyun } else {
1867*4882a593Smuzhiyun pr_debug(", ");
1868*4882a593Smuzhiyun }
1869*4882a593Smuzhiyun
1870*4882a593Smuzhiyun pr_debug("%s", sc);
1871*4882a593Smuzhiyun continue;
1872*4882a593Smuzhiyun }
1873*4882a593Smuzhiyun matches:
1874*4882a593Smuzhiyun trace->ev_qualifier_ids.entries[nr_used++] = id;
1875*4882a593Smuzhiyun if (match_next == -1)
1876*4882a593Smuzhiyun continue;
1877*4882a593Smuzhiyun
1878*4882a593Smuzhiyun while (1) {
1879*4882a593Smuzhiyun id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1880*4882a593Smuzhiyun if (id < 0)
1881*4882a593Smuzhiyun break;
1882*4882a593Smuzhiyun if (nr_allocated == nr_used) {
1883*4882a593Smuzhiyun void *entries;
1884*4882a593Smuzhiyun
1885*4882a593Smuzhiyun nr_allocated += 8;
1886*4882a593Smuzhiyun entries = realloc(trace->ev_qualifier_ids.entries,
1887*4882a593Smuzhiyun nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1888*4882a593Smuzhiyun if (entries == NULL) {
1889*4882a593Smuzhiyun err = -ENOMEM;
1890*4882a593Smuzhiyun fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1891*4882a593Smuzhiyun goto out_free;
1892*4882a593Smuzhiyun }
1893*4882a593Smuzhiyun trace->ev_qualifier_ids.entries = entries;
1894*4882a593Smuzhiyun }
1895*4882a593Smuzhiyun trace->ev_qualifier_ids.entries[nr_used++] = id;
1896*4882a593Smuzhiyun }
1897*4882a593Smuzhiyun }
1898*4882a593Smuzhiyun
1899*4882a593Smuzhiyun trace->ev_qualifier_ids.nr = nr_used;
1900*4882a593Smuzhiyun qsort(trace->ev_qualifier_ids.entries, nr_used, sizeof(int), intcmp);
1901*4882a593Smuzhiyun out:
1902*4882a593Smuzhiyun if (printed_invalid_prefix)
1903*4882a593Smuzhiyun pr_debug("\n");
1904*4882a593Smuzhiyun return err;
1905*4882a593Smuzhiyun out_free:
1906*4882a593Smuzhiyun zfree(&trace->ev_qualifier_ids.entries);
1907*4882a593Smuzhiyun trace->ev_qualifier_ids.nr = 0;
1908*4882a593Smuzhiyun goto out;
1909*4882a593Smuzhiyun }
1910*4882a593Smuzhiyun
trace__syscall_enabled(struct trace * trace,int id)1911*4882a593Smuzhiyun static __maybe_unused bool trace__syscall_enabled(struct trace *trace, int id)
1912*4882a593Smuzhiyun {
1913*4882a593Smuzhiyun bool in_ev_qualifier;
1914*4882a593Smuzhiyun
1915*4882a593Smuzhiyun if (trace->ev_qualifier_ids.nr == 0)
1916*4882a593Smuzhiyun return true;
1917*4882a593Smuzhiyun
1918*4882a593Smuzhiyun in_ev_qualifier = bsearch(&id, trace->ev_qualifier_ids.entries,
1919*4882a593Smuzhiyun trace->ev_qualifier_ids.nr, sizeof(int), intcmp) != NULL;
1920*4882a593Smuzhiyun
1921*4882a593Smuzhiyun if (in_ev_qualifier)
1922*4882a593Smuzhiyun return !trace->not_ev_qualifier;
1923*4882a593Smuzhiyun
1924*4882a593Smuzhiyun return trace->not_ev_qualifier;
1925*4882a593Smuzhiyun }
1926*4882a593Smuzhiyun
1927*4882a593Smuzhiyun /*
1928*4882a593Smuzhiyun * args is to be interpreted as a series of longs but we need to handle
1929*4882a593Smuzhiyun * 8-byte unaligned accesses. args points to raw_data within the event
1930*4882a593Smuzhiyun * and raw_data is guaranteed to be 8-byte unaligned because it is
1931*4882a593Smuzhiyun * preceded by raw_size which is a u32. So we need to copy args to a temp
1932*4882a593Smuzhiyun * variable to read it. Most notably this avoids extended load instructions
1933*4882a593Smuzhiyun * on unaligned addresses
1934*4882a593Smuzhiyun */
syscall_arg__val(struct syscall_arg * arg,u8 idx)1935*4882a593Smuzhiyun unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
1936*4882a593Smuzhiyun {
1937*4882a593Smuzhiyun unsigned long val;
1938*4882a593Smuzhiyun unsigned char *p = arg->args + sizeof(unsigned long) * idx;
1939*4882a593Smuzhiyun
1940*4882a593Smuzhiyun memcpy(&val, p, sizeof(val));
1941*4882a593Smuzhiyun return val;
1942*4882a593Smuzhiyun }
1943*4882a593Smuzhiyun
syscall__scnprintf_name(struct syscall * sc,char * bf,size_t size,struct syscall_arg * arg)1944*4882a593Smuzhiyun static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1945*4882a593Smuzhiyun struct syscall_arg *arg)
1946*4882a593Smuzhiyun {
1947*4882a593Smuzhiyun if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1948*4882a593Smuzhiyun return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1949*4882a593Smuzhiyun
1950*4882a593Smuzhiyun return scnprintf(bf, size, "arg%d: ", arg->idx);
1951*4882a593Smuzhiyun }
1952*4882a593Smuzhiyun
1953*4882a593Smuzhiyun /*
1954*4882a593Smuzhiyun * Check if the value is in fact zero, i.e. mask whatever needs masking, such
1955*4882a593Smuzhiyun * as mount 'flags' argument that needs ignoring some magic flag, see comment
1956*4882a593Smuzhiyun * in tools/perf/trace/beauty/mount_flags.c
1957*4882a593Smuzhiyun */
syscall_arg_fmt__mask_val(struct syscall_arg_fmt * fmt,struct syscall_arg * arg,unsigned long val)1958*4882a593Smuzhiyun static unsigned long syscall_arg_fmt__mask_val(struct syscall_arg_fmt *fmt, struct syscall_arg *arg, unsigned long val)
1959*4882a593Smuzhiyun {
1960*4882a593Smuzhiyun if (fmt && fmt->mask_val)
1961*4882a593Smuzhiyun return fmt->mask_val(arg, val);
1962*4882a593Smuzhiyun
1963*4882a593Smuzhiyun return val;
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun
syscall_arg_fmt__scnprintf_val(struct syscall_arg_fmt * fmt,char * bf,size_t size,struct syscall_arg * arg,unsigned long val)1966*4882a593Smuzhiyun static size_t syscall_arg_fmt__scnprintf_val(struct syscall_arg_fmt *fmt, char *bf, size_t size,
1967*4882a593Smuzhiyun struct syscall_arg *arg, unsigned long val)
1968*4882a593Smuzhiyun {
1969*4882a593Smuzhiyun if (fmt && fmt->scnprintf) {
1970*4882a593Smuzhiyun arg->val = val;
1971*4882a593Smuzhiyun if (fmt->parm)
1972*4882a593Smuzhiyun arg->parm = fmt->parm;
1973*4882a593Smuzhiyun return fmt->scnprintf(bf, size, arg);
1974*4882a593Smuzhiyun }
1975*4882a593Smuzhiyun return scnprintf(bf, size, "%ld", val);
1976*4882a593Smuzhiyun }
1977*4882a593Smuzhiyun
syscall__scnprintf_args(struct syscall * sc,char * bf,size_t size,unsigned char * args,void * augmented_args,int augmented_args_size,struct trace * trace,struct thread * thread)1978*4882a593Smuzhiyun static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
1979*4882a593Smuzhiyun unsigned char *args, void *augmented_args, int augmented_args_size,
1980*4882a593Smuzhiyun struct trace *trace, struct thread *thread)
1981*4882a593Smuzhiyun {
1982*4882a593Smuzhiyun size_t printed = 0;
1983*4882a593Smuzhiyun unsigned long val;
1984*4882a593Smuzhiyun u8 bit = 1;
1985*4882a593Smuzhiyun struct syscall_arg arg = {
1986*4882a593Smuzhiyun .args = args,
1987*4882a593Smuzhiyun .augmented = {
1988*4882a593Smuzhiyun .size = augmented_args_size,
1989*4882a593Smuzhiyun .args = augmented_args,
1990*4882a593Smuzhiyun },
1991*4882a593Smuzhiyun .idx = 0,
1992*4882a593Smuzhiyun .mask = 0,
1993*4882a593Smuzhiyun .trace = trace,
1994*4882a593Smuzhiyun .thread = thread,
1995*4882a593Smuzhiyun .show_string_prefix = trace->show_string_prefix,
1996*4882a593Smuzhiyun };
1997*4882a593Smuzhiyun struct thread_trace *ttrace = thread__priv(thread);
1998*4882a593Smuzhiyun
1999*4882a593Smuzhiyun /*
2000*4882a593Smuzhiyun * Things like fcntl will set this in its 'cmd' formatter to pick the
2001*4882a593Smuzhiyun * right formatter for the return value (an fd? file flags?), which is
2002*4882a593Smuzhiyun * not needed for syscalls that always return a given type, say an fd.
2003*4882a593Smuzhiyun */
2004*4882a593Smuzhiyun ttrace->ret_scnprintf = NULL;
2005*4882a593Smuzhiyun
2006*4882a593Smuzhiyun if (sc->args != NULL) {
2007*4882a593Smuzhiyun struct tep_format_field *field;
2008*4882a593Smuzhiyun
2009*4882a593Smuzhiyun for (field = sc->args; field;
2010*4882a593Smuzhiyun field = field->next, ++arg.idx, bit <<= 1) {
2011*4882a593Smuzhiyun if (arg.mask & bit)
2012*4882a593Smuzhiyun continue;
2013*4882a593Smuzhiyun
2014*4882a593Smuzhiyun arg.fmt = &sc->arg_fmt[arg.idx];
2015*4882a593Smuzhiyun val = syscall_arg__val(&arg, arg.idx);
2016*4882a593Smuzhiyun /*
2017*4882a593Smuzhiyun * Some syscall args need some mask, most don't and
2018*4882a593Smuzhiyun * return val untouched.
2019*4882a593Smuzhiyun */
2020*4882a593Smuzhiyun val = syscall_arg_fmt__mask_val(&sc->arg_fmt[arg.idx], &arg, val);
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun /*
2023*4882a593Smuzhiyun * Suppress this argument if its value is zero and
2024*4882a593Smuzhiyun * and we don't have a string associated in an
2025*4882a593Smuzhiyun * strarray for it.
2026*4882a593Smuzhiyun */
2027*4882a593Smuzhiyun if (val == 0 &&
2028*4882a593Smuzhiyun !trace->show_zeros &&
2029*4882a593Smuzhiyun !(sc->arg_fmt &&
2030*4882a593Smuzhiyun (sc->arg_fmt[arg.idx].show_zero ||
2031*4882a593Smuzhiyun sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
2032*4882a593Smuzhiyun sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
2033*4882a593Smuzhiyun sc->arg_fmt[arg.idx].parm))
2034*4882a593Smuzhiyun continue;
2035*4882a593Smuzhiyun
2036*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
2037*4882a593Smuzhiyun
2038*4882a593Smuzhiyun if (trace->show_arg_names)
2039*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
2040*4882a593Smuzhiyun
2041*4882a593Smuzhiyun printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx],
2042*4882a593Smuzhiyun bf + printed, size - printed, &arg, val);
2043*4882a593Smuzhiyun }
2044*4882a593Smuzhiyun } else if (IS_ERR(sc->tp_format)) {
2045*4882a593Smuzhiyun /*
2046*4882a593Smuzhiyun * If we managed to read the tracepoint /format file, then we
2047*4882a593Smuzhiyun * may end up not having any args, like with gettid(), so only
2048*4882a593Smuzhiyun * print the raw args when we didn't manage to read it.
2049*4882a593Smuzhiyun */
2050*4882a593Smuzhiyun while (arg.idx < sc->nr_args) {
2051*4882a593Smuzhiyun if (arg.mask & bit)
2052*4882a593Smuzhiyun goto next_arg;
2053*4882a593Smuzhiyun val = syscall_arg__val(&arg, arg.idx);
2054*4882a593Smuzhiyun if (printed)
2055*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, ", ");
2056*4882a593Smuzhiyun printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
2057*4882a593Smuzhiyun printed += syscall_arg_fmt__scnprintf_val(&sc->arg_fmt[arg.idx], bf + printed, size - printed, &arg, val);
2058*4882a593Smuzhiyun next_arg:
2059*4882a593Smuzhiyun ++arg.idx;
2060*4882a593Smuzhiyun bit <<= 1;
2061*4882a593Smuzhiyun }
2062*4882a593Smuzhiyun }
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun return printed;
2065*4882a593Smuzhiyun }
2066*4882a593Smuzhiyun
2067*4882a593Smuzhiyun typedef int (*tracepoint_handler)(struct trace *trace, struct evsel *evsel,
2068*4882a593Smuzhiyun union perf_event *event,
2069*4882a593Smuzhiyun struct perf_sample *sample);
2070*4882a593Smuzhiyun
trace__syscall_info(struct trace * trace,struct evsel * evsel,int id)2071*4882a593Smuzhiyun static struct syscall *trace__syscall_info(struct trace *trace,
2072*4882a593Smuzhiyun struct evsel *evsel, int id)
2073*4882a593Smuzhiyun {
2074*4882a593Smuzhiyun int err = 0;
2075*4882a593Smuzhiyun
2076*4882a593Smuzhiyun if (id < 0) {
2077*4882a593Smuzhiyun
2078*4882a593Smuzhiyun /*
2079*4882a593Smuzhiyun * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
2080*4882a593Smuzhiyun * before that, leaving at a higher verbosity level till that is
2081*4882a593Smuzhiyun * explained. Reproduced with plain ftrace with:
2082*4882a593Smuzhiyun *
2083*4882a593Smuzhiyun * echo 1 > /t/events/raw_syscalls/sys_exit/enable
2084*4882a593Smuzhiyun * grep "NR -1 " /t/trace_pipe
2085*4882a593Smuzhiyun *
2086*4882a593Smuzhiyun * After generating some load on the machine.
2087*4882a593Smuzhiyun */
2088*4882a593Smuzhiyun if (verbose > 1) {
2089*4882a593Smuzhiyun static u64 n;
2090*4882a593Smuzhiyun fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
2091*4882a593Smuzhiyun id, evsel__name(evsel), ++n);
2092*4882a593Smuzhiyun }
2093*4882a593Smuzhiyun return NULL;
2094*4882a593Smuzhiyun }
2095*4882a593Smuzhiyun
2096*4882a593Smuzhiyun err = -EINVAL;
2097*4882a593Smuzhiyun
2098*4882a593Smuzhiyun #ifdef HAVE_SYSCALL_TABLE_SUPPORT
2099*4882a593Smuzhiyun if (id > trace->sctbl->syscalls.max_id) {
2100*4882a593Smuzhiyun #else
2101*4882a593Smuzhiyun if (id >= trace->sctbl->syscalls.max_id) {
2102*4882a593Smuzhiyun /*
2103*4882a593Smuzhiyun * With libaudit we don't know beforehand what is the max_id,
2104*4882a593Smuzhiyun * so we let trace__read_syscall_info() figure that out as we
2105*4882a593Smuzhiyun * go on reading syscalls.
2106*4882a593Smuzhiyun */
2107*4882a593Smuzhiyun err = trace__read_syscall_info(trace, id);
2108*4882a593Smuzhiyun if (err)
2109*4882a593Smuzhiyun #endif
2110*4882a593Smuzhiyun goto out_cant_read;
2111*4882a593Smuzhiyun }
2112*4882a593Smuzhiyun
2113*4882a593Smuzhiyun if ((trace->syscalls.table == NULL || trace->syscalls.table[id].name == NULL) &&
2114*4882a593Smuzhiyun (err = trace__read_syscall_info(trace, id)) != 0)
2115*4882a593Smuzhiyun goto out_cant_read;
2116*4882a593Smuzhiyun
2117*4882a593Smuzhiyun if (trace->syscalls.table[id].name == NULL) {
2118*4882a593Smuzhiyun if (trace->syscalls.table[id].nonexistent)
2119*4882a593Smuzhiyun return NULL;
2120*4882a593Smuzhiyun goto out_cant_read;
2121*4882a593Smuzhiyun }
2122*4882a593Smuzhiyun
2123*4882a593Smuzhiyun return &trace->syscalls.table[id];
2124*4882a593Smuzhiyun
2125*4882a593Smuzhiyun out_cant_read:
2126*4882a593Smuzhiyun if (verbose > 0) {
2127*4882a593Smuzhiyun char sbuf[STRERR_BUFSIZE];
2128*4882a593Smuzhiyun fprintf(trace->output, "Problems reading syscall %d: %d (%s)", id, -err, str_error_r(-err, sbuf, sizeof(sbuf)));
2129*4882a593Smuzhiyun if (id <= trace->sctbl->syscalls.max_id && trace->syscalls.table[id].name != NULL)
2130*4882a593Smuzhiyun fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
2131*4882a593Smuzhiyun fputs(" information\n", trace->output);
2132*4882a593Smuzhiyun }
2133*4882a593Smuzhiyun return NULL;
2134*4882a593Smuzhiyun }
2135*4882a593Smuzhiyun
2136*4882a593Smuzhiyun struct syscall_stats {
2137*4882a593Smuzhiyun struct stats stats;
2138*4882a593Smuzhiyun u64 nr_failures;
2139*4882a593Smuzhiyun int max_errno;
2140*4882a593Smuzhiyun u32 *errnos;
2141*4882a593Smuzhiyun };
2142*4882a593Smuzhiyun
2143*4882a593Smuzhiyun static void thread__update_stats(struct thread *thread, struct thread_trace *ttrace,
2144*4882a593Smuzhiyun int id, struct perf_sample *sample, long err, bool errno_summary)
2145*4882a593Smuzhiyun {
2146*4882a593Smuzhiyun struct int_node *inode;
2147*4882a593Smuzhiyun struct syscall_stats *stats;
2148*4882a593Smuzhiyun u64 duration = 0;
2149*4882a593Smuzhiyun
2150*4882a593Smuzhiyun inode = intlist__findnew(ttrace->syscall_stats, id);
2151*4882a593Smuzhiyun if (inode == NULL)
2152*4882a593Smuzhiyun return;
2153*4882a593Smuzhiyun
2154*4882a593Smuzhiyun stats = inode->priv;
2155*4882a593Smuzhiyun if (stats == NULL) {
2156*4882a593Smuzhiyun stats = malloc(sizeof(*stats));
2157*4882a593Smuzhiyun if (stats == NULL)
2158*4882a593Smuzhiyun return;
2159*4882a593Smuzhiyun
2160*4882a593Smuzhiyun stats->nr_failures = 0;
2161*4882a593Smuzhiyun stats->max_errno = 0;
2162*4882a593Smuzhiyun stats->errnos = NULL;
2163*4882a593Smuzhiyun init_stats(&stats->stats);
2164*4882a593Smuzhiyun inode->priv = stats;
2165*4882a593Smuzhiyun }
2166*4882a593Smuzhiyun
2167*4882a593Smuzhiyun if (ttrace->entry_time && sample->time > ttrace->entry_time)
2168*4882a593Smuzhiyun duration = sample->time - ttrace->entry_time;
2169*4882a593Smuzhiyun
2170*4882a593Smuzhiyun update_stats(&stats->stats, duration);
2171*4882a593Smuzhiyun
2172*4882a593Smuzhiyun if (err < 0) {
2173*4882a593Smuzhiyun ++stats->nr_failures;
2174*4882a593Smuzhiyun
2175*4882a593Smuzhiyun if (!errno_summary)
2176*4882a593Smuzhiyun return;
2177*4882a593Smuzhiyun
2178*4882a593Smuzhiyun err = -err;
2179*4882a593Smuzhiyun if (err > stats->max_errno) {
2180*4882a593Smuzhiyun u32 *new_errnos = realloc(stats->errnos, err * sizeof(u32));
2181*4882a593Smuzhiyun
2182*4882a593Smuzhiyun if (new_errnos) {
2183*4882a593Smuzhiyun memset(new_errnos + stats->max_errno, 0, (err - stats->max_errno) * sizeof(u32));
2184*4882a593Smuzhiyun } else {
2185*4882a593Smuzhiyun pr_debug("Not enough memory for errno stats for thread \"%s\"(%d/%d), results will be incomplete\n",
2186*4882a593Smuzhiyun thread__comm_str(thread), thread->pid_, thread->tid);
2187*4882a593Smuzhiyun return;
2188*4882a593Smuzhiyun }
2189*4882a593Smuzhiyun
2190*4882a593Smuzhiyun stats->errnos = new_errnos;
2191*4882a593Smuzhiyun stats->max_errno = err;
2192*4882a593Smuzhiyun }
2193*4882a593Smuzhiyun
2194*4882a593Smuzhiyun ++stats->errnos[err - 1];
2195*4882a593Smuzhiyun }
2196*4882a593Smuzhiyun }
2197*4882a593Smuzhiyun
2198*4882a593Smuzhiyun static int trace__printf_interrupted_entry(struct trace *trace)
2199*4882a593Smuzhiyun {
2200*4882a593Smuzhiyun struct thread_trace *ttrace;
2201*4882a593Smuzhiyun size_t printed;
2202*4882a593Smuzhiyun int len;
2203*4882a593Smuzhiyun
2204*4882a593Smuzhiyun if (trace->failure_only || trace->current == NULL)
2205*4882a593Smuzhiyun return 0;
2206*4882a593Smuzhiyun
2207*4882a593Smuzhiyun ttrace = thread__priv(trace->current);
2208*4882a593Smuzhiyun
2209*4882a593Smuzhiyun if (!ttrace->entry_pending)
2210*4882a593Smuzhiyun return 0;
2211*4882a593Smuzhiyun
2212*4882a593Smuzhiyun printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
2213*4882a593Smuzhiyun printed += len = fprintf(trace->output, "%s)", ttrace->entry_str);
2214*4882a593Smuzhiyun
2215*4882a593Smuzhiyun if (len < trace->args_alignment - 4)
2216*4882a593Smuzhiyun printed += fprintf(trace->output, "%-*s", trace->args_alignment - 4 - len, " ");
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun printed += fprintf(trace->output, " ...\n");
2219*4882a593Smuzhiyun
2220*4882a593Smuzhiyun ttrace->entry_pending = false;
2221*4882a593Smuzhiyun ++trace->nr_events_printed;
2222*4882a593Smuzhiyun
2223*4882a593Smuzhiyun return printed;
2224*4882a593Smuzhiyun }
2225*4882a593Smuzhiyun
2226*4882a593Smuzhiyun static int trace__fprintf_sample(struct trace *trace, struct evsel *evsel,
2227*4882a593Smuzhiyun struct perf_sample *sample, struct thread *thread)
2228*4882a593Smuzhiyun {
2229*4882a593Smuzhiyun int printed = 0;
2230*4882a593Smuzhiyun
2231*4882a593Smuzhiyun if (trace->print_sample) {
2232*4882a593Smuzhiyun double ts = (double)sample->time / NSEC_PER_MSEC;
2233*4882a593Smuzhiyun
2234*4882a593Smuzhiyun printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
2235*4882a593Smuzhiyun evsel__name(evsel), ts,
2236*4882a593Smuzhiyun thread__comm_str(thread),
2237*4882a593Smuzhiyun sample->pid, sample->tid, sample->cpu);
2238*4882a593Smuzhiyun }
2239*4882a593Smuzhiyun
2240*4882a593Smuzhiyun return printed;
2241*4882a593Smuzhiyun }
2242*4882a593Smuzhiyun
2243*4882a593Smuzhiyun static void *syscall__augmented_args(struct syscall *sc, struct perf_sample *sample, int *augmented_args_size, int raw_augmented_args_size)
2244*4882a593Smuzhiyun {
2245*4882a593Smuzhiyun void *augmented_args = NULL;
2246*4882a593Smuzhiyun /*
2247*4882a593Smuzhiyun * For now with BPF raw_augmented we hook into raw_syscalls:sys_enter
2248*4882a593Smuzhiyun * and there we get all 6 syscall args plus the tracepoint common fields
2249*4882a593Smuzhiyun * that gets calculated at the start and the syscall_nr (another long).
2250*4882a593Smuzhiyun * So we check if that is the case and if so don't look after the
2251*4882a593Smuzhiyun * sc->args_size but always after the full raw_syscalls:sys_enter payload,
2252*4882a593Smuzhiyun * which is fixed.
2253*4882a593Smuzhiyun *
2254*4882a593Smuzhiyun * We'll revisit this later to pass s->args_size to the BPF augmenter
2255*4882a593Smuzhiyun * (now tools/perf/examples/bpf/augmented_raw_syscalls.c, so that it
2256*4882a593Smuzhiyun * copies only what we need for each syscall, like what happens when we
2257*4882a593Smuzhiyun * use syscalls:sys_enter_NAME, so that we reduce the kernel/userspace
2258*4882a593Smuzhiyun * traffic to just what is needed for each syscall.
2259*4882a593Smuzhiyun */
2260*4882a593Smuzhiyun int args_size = raw_augmented_args_size ?: sc->args_size;
2261*4882a593Smuzhiyun
2262*4882a593Smuzhiyun *augmented_args_size = sample->raw_size - args_size;
2263*4882a593Smuzhiyun if (*augmented_args_size > 0)
2264*4882a593Smuzhiyun augmented_args = sample->raw_data + args_size;
2265*4882a593Smuzhiyun
2266*4882a593Smuzhiyun return augmented_args;
2267*4882a593Smuzhiyun }
2268*4882a593Smuzhiyun
2269*4882a593Smuzhiyun static int trace__sys_enter(struct trace *trace, struct evsel *evsel,
2270*4882a593Smuzhiyun union perf_event *event __maybe_unused,
2271*4882a593Smuzhiyun struct perf_sample *sample)
2272*4882a593Smuzhiyun {
2273*4882a593Smuzhiyun char *msg;
2274*4882a593Smuzhiyun void *args;
2275*4882a593Smuzhiyun int printed = 0;
2276*4882a593Smuzhiyun struct thread *thread;
2277*4882a593Smuzhiyun int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
2278*4882a593Smuzhiyun int augmented_args_size = 0;
2279*4882a593Smuzhiyun void *augmented_args = NULL;
2280*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, evsel, id);
2281*4882a593Smuzhiyun struct thread_trace *ttrace;
2282*4882a593Smuzhiyun
2283*4882a593Smuzhiyun if (sc == NULL)
2284*4882a593Smuzhiyun return -1;
2285*4882a593Smuzhiyun
2286*4882a593Smuzhiyun thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2287*4882a593Smuzhiyun ttrace = thread__trace(thread, trace->output);
2288*4882a593Smuzhiyun if (ttrace == NULL)
2289*4882a593Smuzhiyun goto out_put;
2290*4882a593Smuzhiyun
2291*4882a593Smuzhiyun trace__fprintf_sample(trace, evsel, sample, thread);
2292*4882a593Smuzhiyun
2293*4882a593Smuzhiyun args = perf_evsel__sc_tp_ptr(evsel, args, sample);
2294*4882a593Smuzhiyun
2295*4882a593Smuzhiyun if (ttrace->entry_str == NULL) {
2296*4882a593Smuzhiyun ttrace->entry_str = malloc(trace__entry_str_size);
2297*4882a593Smuzhiyun if (!ttrace->entry_str)
2298*4882a593Smuzhiyun goto out_put;
2299*4882a593Smuzhiyun }
2300*4882a593Smuzhiyun
2301*4882a593Smuzhiyun if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
2302*4882a593Smuzhiyun trace__printf_interrupted_entry(trace);
2303*4882a593Smuzhiyun /*
2304*4882a593Smuzhiyun * If this is raw_syscalls.sys_enter, then it always comes with the 6 possible
2305*4882a593Smuzhiyun * arguments, even if the syscall being handled, say "openat", uses only 4 arguments
2306*4882a593Smuzhiyun * this breaks syscall__augmented_args() check for augmented args, as we calculate
2307*4882a593Smuzhiyun * syscall->args_size using each syscalls:sys_enter_NAME tracefs format file,
2308*4882a593Smuzhiyun * so when handling, say the openat syscall, we end up getting 6 args for the
2309*4882a593Smuzhiyun * raw_syscalls:sys_enter event, when we expected just 4, we end up mistakenly
2310*4882a593Smuzhiyun * thinking that the extra 2 u64 args are the augmented filename, so just check
2311*4882a593Smuzhiyun * here and avoid using augmented syscalls when the evsel is the raw_syscalls one.
2312*4882a593Smuzhiyun */
2313*4882a593Smuzhiyun if (evsel != trace->syscalls.events.sys_enter)
2314*4882a593Smuzhiyun augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
2315*4882a593Smuzhiyun ttrace->entry_time = sample->time;
2316*4882a593Smuzhiyun msg = ttrace->entry_str;
2317*4882a593Smuzhiyun printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
2318*4882a593Smuzhiyun
2319*4882a593Smuzhiyun printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
2320*4882a593Smuzhiyun args, augmented_args, augmented_args_size, trace, thread);
2321*4882a593Smuzhiyun
2322*4882a593Smuzhiyun if (sc->is_exit) {
2323*4882a593Smuzhiyun if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
2324*4882a593Smuzhiyun int alignment = 0;
2325*4882a593Smuzhiyun
2326*4882a593Smuzhiyun trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
2327*4882a593Smuzhiyun printed = fprintf(trace->output, "%s)", ttrace->entry_str);
2328*4882a593Smuzhiyun if (trace->args_alignment > printed)
2329*4882a593Smuzhiyun alignment = trace->args_alignment - printed;
2330*4882a593Smuzhiyun fprintf(trace->output, "%*s= ?\n", alignment, " ");
2331*4882a593Smuzhiyun }
2332*4882a593Smuzhiyun } else {
2333*4882a593Smuzhiyun ttrace->entry_pending = true;
2334*4882a593Smuzhiyun /* See trace__vfs_getname & trace__sys_exit */
2335*4882a593Smuzhiyun ttrace->filename.pending_open = false;
2336*4882a593Smuzhiyun }
2337*4882a593Smuzhiyun
2338*4882a593Smuzhiyun if (trace->current != thread) {
2339*4882a593Smuzhiyun thread__put(trace->current);
2340*4882a593Smuzhiyun trace->current = thread__get(thread);
2341*4882a593Smuzhiyun }
2342*4882a593Smuzhiyun err = 0;
2343*4882a593Smuzhiyun out_put:
2344*4882a593Smuzhiyun thread__put(thread);
2345*4882a593Smuzhiyun return err;
2346*4882a593Smuzhiyun }
2347*4882a593Smuzhiyun
2348*4882a593Smuzhiyun static int trace__fprintf_sys_enter(struct trace *trace, struct evsel *evsel,
2349*4882a593Smuzhiyun struct perf_sample *sample)
2350*4882a593Smuzhiyun {
2351*4882a593Smuzhiyun struct thread_trace *ttrace;
2352*4882a593Smuzhiyun struct thread *thread;
2353*4882a593Smuzhiyun int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
2354*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, evsel, id);
2355*4882a593Smuzhiyun char msg[1024];
2356*4882a593Smuzhiyun void *args, *augmented_args = NULL;
2357*4882a593Smuzhiyun int augmented_args_size;
2358*4882a593Smuzhiyun
2359*4882a593Smuzhiyun if (sc == NULL)
2360*4882a593Smuzhiyun return -1;
2361*4882a593Smuzhiyun
2362*4882a593Smuzhiyun thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2363*4882a593Smuzhiyun ttrace = thread__trace(thread, trace->output);
2364*4882a593Smuzhiyun /*
2365*4882a593Smuzhiyun * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
2366*4882a593Smuzhiyun * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
2367*4882a593Smuzhiyun */
2368*4882a593Smuzhiyun if (ttrace == NULL)
2369*4882a593Smuzhiyun goto out_put;
2370*4882a593Smuzhiyun
2371*4882a593Smuzhiyun args = perf_evsel__sc_tp_ptr(evsel, args, sample);
2372*4882a593Smuzhiyun augmented_args = syscall__augmented_args(sc, sample, &augmented_args_size, trace->raw_augmented_syscalls_args_size);
2373*4882a593Smuzhiyun syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
2374*4882a593Smuzhiyun fprintf(trace->output, "%s", msg);
2375*4882a593Smuzhiyun err = 0;
2376*4882a593Smuzhiyun out_put:
2377*4882a593Smuzhiyun thread__put(thread);
2378*4882a593Smuzhiyun return err;
2379*4882a593Smuzhiyun }
2380*4882a593Smuzhiyun
2381*4882a593Smuzhiyun static int trace__resolve_callchain(struct trace *trace, struct evsel *evsel,
2382*4882a593Smuzhiyun struct perf_sample *sample,
2383*4882a593Smuzhiyun struct callchain_cursor *cursor)
2384*4882a593Smuzhiyun {
2385*4882a593Smuzhiyun struct addr_location al;
2386*4882a593Smuzhiyun int max_stack = evsel->core.attr.sample_max_stack ?
2387*4882a593Smuzhiyun evsel->core.attr.sample_max_stack :
2388*4882a593Smuzhiyun trace->max_stack;
2389*4882a593Smuzhiyun int err;
2390*4882a593Smuzhiyun
2391*4882a593Smuzhiyun if (machine__resolve(trace->host, &al, sample) < 0)
2392*4882a593Smuzhiyun return -1;
2393*4882a593Smuzhiyun
2394*4882a593Smuzhiyun err = thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack);
2395*4882a593Smuzhiyun addr_location__put(&al);
2396*4882a593Smuzhiyun return err;
2397*4882a593Smuzhiyun }
2398*4882a593Smuzhiyun
2399*4882a593Smuzhiyun static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
2400*4882a593Smuzhiyun {
2401*4882a593Smuzhiyun /* TODO: user-configurable print_opts */
2402*4882a593Smuzhiyun const unsigned int print_opts = EVSEL__PRINT_SYM |
2403*4882a593Smuzhiyun EVSEL__PRINT_DSO |
2404*4882a593Smuzhiyun EVSEL__PRINT_UNKNOWN_AS_ADDR;
2405*4882a593Smuzhiyun
2406*4882a593Smuzhiyun return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, symbol_conf.bt_stop_list, trace->output);
2407*4882a593Smuzhiyun }
2408*4882a593Smuzhiyun
2409*4882a593Smuzhiyun static const char *errno_to_name(struct evsel *evsel, int err)
2410*4882a593Smuzhiyun {
2411*4882a593Smuzhiyun struct perf_env *env = evsel__env(evsel);
2412*4882a593Smuzhiyun const char *arch_name = perf_env__arch(env);
2413*4882a593Smuzhiyun
2414*4882a593Smuzhiyun return arch_syscalls__strerrno(arch_name, err);
2415*4882a593Smuzhiyun }
2416*4882a593Smuzhiyun
2417*4882a593Smuzhiyun static int trace__sys_exit(struct trace *trace, struct evsel *evsel,
2418*4882a593Smuzhiyun union perf_event *event __maybe_unused,
2419*4882a593Smuzhiyun struct perf_sample *sample)
2420*4882a593Smuzhiyun {
2421*4882a593Smuzhiyun long ret;
2422*4882a593Smuzhiyun u64 duration = 0;
2423*4882a593Smuzhiyun bool duration_calculated = false;
2424*4882a593Smuzhiyun struct thread *thread;
2425*4882a593Smuzhiyun int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0, printed = 0;
2426*4882a593Smuzhiyun int alignment = trace->args_alignment;
2427*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, evsel, id);
2428*4882a593Smuzhiyun struct thread_trace *ttrace;
2429*4882a593Smuzhiyun
2430*4882a593Smuzhiyun if (sc == NULL)
2431*4882a593Smuzhiyun return -1;
2432*4882a593Smuzhiyun
2433*4882a593Smuzhiyun thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2434*4882a593Smuzhiyun ttrace = thread__trace(thread, trace->output);
2435*4882a593Smuzhiyun if (ttrace == NULL)
2436*4882a593Smuzhiyun goto out_put;
2437*4882a593Smuzhiyun
2438*4882a593Smuzhiyun trace__fprintf_sample(trace, evsel, sample, thread);
2439*4882a593Smuzhiyun
2440*4882a593Smuzhiyun ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
2441*4882a593Smuzhiyun
2442*4882a593Smuzhiyun if (trace->summary)
2443*4882a593Smuzhiyun thread__update_stats(thread, ttrace, id, sample, ret, trace->errno_summary);
2444*4882a593Smuzhiyun
2445*4882a593Smuzhiyun if (!trace->fd_path_disabled && sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
2446*4882a593Smuzhiyun trace__set_fd_pathname(thread, ret, ttrace->filename.name);
2447*4882a593Smuzhiyun ttrace->filename.pending_open = false;
2448*4882a593Smuzhiyun ++trace->stats.vfs_getname;
2449*4882a593Smuzhiyun }
2450*4882a593Smuzhiyun
2451*4882a593Smuzhiyun if (ttrace->entry_time) {
2452*4882a593Smuzhiyun duration = sample->time - ttrace->entry_time;
2453*4882a593Smuzhiyun if (trace__filter_duration(trace, duration))
2454*4882a593Smuzhiyun goto out;
2455*4882a593Smuzhiyun duration_calculated = true;
2456*4882a593Smuzhiyun } else if (trace->duration_filter)
2457*4882a593Smuzhiyun goto out;
2458*4882a593Smuzhiyun
2459*4882a593Smuzhiyun if (sample->callchain) {
2460*4882a593Smuzhiyun callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2461*4882a593Smuzhiyun if (callchain_ret == 0) {
2462*4882a593Smuzhiyun if (callchain_cursor.nr < trace->min_stack)
2463*4882a593Smuzhiyun goto out;
2464*4882a593Smuzhiyun callchain_ret = 1;
2465*4882a593Smuzhiyun }
2466*4882a593Smuzhiyun }
2467*4882a593Smuzhiyun
2468*4882a593Smuzhiyun if (trace->summary_only || (ret >= 0 && trace->failure_only))
2469*4882a593Smuzhiyun goto out;
2470*4882a593Smuzhiyun
2471*4882a593Smuzhiyun trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
2472*4882a593Smuzhiyun
2473*4882a593Smuzhiyun if (ttrace->entry_pending) {
2474*4882a593Smuzhiyun printed = fprintf(trace->output, "%s", ttrace->entry_str);
2475*4882a593Smuzhiyun } else {
2476*4882a593Smuzhiyun printed += fprintf(trace->output, " ... [");
2477*4882a593Smuzhiyun color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2478*4882a593Smuzhiyun printed += 9;
2479*4882a593Smuzhiyun printed += fprintf(trace->output, "]: %s()", sc->name);
2480*4882a593Smuzhiyun }
2481*4882a593Smuzhiyun
2482*4882a593Smuzhiyun printed++; /* the closing ')' */
2483*4882a593Smuzhiyun
2484*4882a593Smuzhiyun if (alignment > printed)
2485*4882a593Smuzhiyun alignment -= printed;
2486*4882a593Smuzhiyun else
2487*4882a593Smuzhiyun alignment = 0;
2488*4882a593Smuzhiyun
2489*4882a593Smuzhiyun fprintf(trace->output, ")%*s= ", alignment, " ");
2490*4882a593Smuzhiyun
2491*4882a593Smuzhiyun if (sc->fmt == NULL) {
2492*4882a593Smuzhiyun if (ret < 0)
2493*4882a593Smuzhiyun goto errno_print;
2494*4882a593Smuzhiyun signed_print:
2495*4882a593Smuzhiyun fprintf(trace->output, "%ld", ret);
2496*4882a593Smuzhiyun } else if (ret < 0) {
2497*4882a593Smuzhiyun errno_print: {
2498*4882a593Smuzhiyun char bf[STRERR_BUFSIZE];
2499*4882a593Smuzhiyun const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
2500*4882a593Smuzhiyun *e = errno_to_name(evsel, -ret);
2501*4882a593Smuzhiyun
2502*4882a593Smuzhiyun fprintf(trace->output, "-1 %s (%s)", e, emsg);
2503*4882a593Smuzhiyun }
2504*4882a593Smuzhiyun } else if (ret == 0 && sc->fmt->timeout)
2505*4882a593Smuzhiyun fprintf(trace->output, "0 (Timeout)");
2506*4882a593Smuzhiyun else if (ttrace->ret_scnprintf) {
2507*4882a593Smuzhiyun char bf[1024];
2508*4882a593Smuzhiyun struct syscall_arg arg = {
2509*4882a593Smuzhiyun .val = ret,
2510*4882a593Smuzhiyun .thread = thread,
2511*4882a593Smuzhiyun .trace = trace,
2512*4882a593Smuzhiyun };
2513*4882a593Smuzhiyun ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
2514*4882a593Smuzhiyun ttrace->ret_scnprintf = NULL;
2515*4882a593Smuzhiyun fprintf(trace->output, "%s", bf);
2516*4882a593Smuzhiyun } else if (sc->fmt->hexret)
2517*4882a593Smuzhiyun fprintf(trace->output, "%#lx", ret);
2518*4882a593Smuzhiyun else if (sc->fmt->errpid) {
2519*4882a593Smuzhiyun struct thread *child = machine__find_thread(trace->host, ret, ret);
2520*4882a593Smuzhiyun
2521*4882a593Smuzhiyun if (child != NULL) {
2522*4882a593Smuzhiyun fprintf(trace->output, "%ld", ret);
2523*4882a593Smuzhiyun if (child->comm_set)
2524*4882a593Smuzhiyun fprintf(trace->output, " (%s)", thread__comm_str(child));
2525*4882a593Smuzhiyun thread__put(child);
2526*4882a593Smuzhiyun }
2527*4882a593Smuzhiyun } else
2528*4882a593Smuzhiyun goto signed_print;
2529*4882a593Smuzhiyun
2530*4882a593Smuzhiyun fputc('\n', trace->output);
2531*4882a593Smuzhiyun
2532*4882a593Smuzhiyun /*
2533*4882a593Smuzhiyun * We only consider an 'event' for the sake of --max-events a non-filtered
2534*4882a593Smuzhiyun * sys_enter + sys_exit and other tracepoint events.
2535*4882a593Smuzhiyun */
2536*4882a593Smuzhiyun if (++trace->nr_events_printed == trace->max_events && trace->max_events != ULONG_MAX)
2537*4882a593Smuzhiyun interrupted = true;
2538*4882a593Smuzhiyun
2539*4882a593Smuzhiyun if (callchain_ret > 0)
2540*4882a593Smuzhiyun trace__fprintf_callchain(trace, sample);
2541*4882a593Smuzhiyun else if (callchain_ret < 0)
2542*4882a593Smuzhiyun pr_err("Problem processing %s callchain, skipping...\n", evsel__name(evsel));
2543*4882a593Smuzhiyun out:
2544*4882a593Smuzhiyun ttrace->entry_pending = false;
2545*4882a593Smuzhiyun err = 0;
2546*4882a593Smuzhiyun out_put:
2547*4882a593Smuzhiyun thread__put(thread);
2548*4882a593Smuzhiyun return err;
2549*4882a593Smuzhiyun }
2550*4882a593Smuzhiyun
2551*4882a593Smuzhiyun static int trace__vfs_getname(struct trace *trace, struct evsel *evsel,
2552*4882a593Smuzhiyun union perf_event *event __maybe_unused,
2553*4882a593Smuzhiyun struct perf_sample *sample)
2554*4882a593Smuzhiyun {
2555*4882a593Smuzhiyun struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2556*4882a593Smuzhiyun struct thread_trace *ttrace;
2557*4882a593Smuzhiyun size_t filename_len, entry_str_len, to_move;
2558*4882a593Smuzhiyun ssize_t remaining_space;
2559*4882a593Smuzhiyun char *pos;
2560*4882a593Smuzhiyun const char *filename = evsel__rawptr(evsel, sample, "pathname");
2561*4882a593Smuzhiyun
2562*4882a593Smuzhiyun if (!thread)
2563*4882a593Smuzhiyun goto out;
2564*4882a593Smuzhiyun
2565*4882a593Smuzhiyun ttrace = thread__priv(thread);
2566*4882a593Smuzhiyun if (!ttrace)
2567*4882a593Smuzhiyun goto out_put;
2568*4882a593Smuzhiyun
2569*4882a593Smuzhiyun filename_len = strlen(filename);
2570*4882a593Smuzhiyun if (filename_len == 0)
2571*4882a593Smuzhiyun goto out_put;
2572*4882a593Smuzhiyun
2573*4882a593Smuzhiyun if (ttrace->filename.namelen < filename_len) {
2574*4882a593Smuzhiyun char *f = realloc(ttrace->filename.name, filename_len + 1);
2575*4882a593Smuzhiyun
2576*4882a593Smuzhiyun if (f == NULL)
2577*4882a593Smuzhiyun goto out_put;
2578*4882a593Smuzhiyun
2579*4882a593Smuzhiyun ttrace->filename.namelen = filename_len;
2580*4882a593Smuzhiyun ttrace->filename.name = f;
2581*4882a593Smuzhiyun }
2582*4882a593Smuzhiyun
2583*4882a593Smuzhiyun strcpy(ttrace->filename.name, filename);
2584*4882a593Smuzhiyun ttrace->filename.pending_open = true;
2585*4882a593Smuzhiyun
2586*4882a593Smuzhiyun if (!ttrace->filename.ptr)
2587*4882a593Smuzhiyun goto out_put;
2588*4882a593Smuzhiyun
2589*4882a593Smuzhiyun entry_str_len = strlen(ttrace->entry_str);
2590*4882a593Smuzhiyun remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2591*4882a593Smuzhiyun if (remaining_space <= 0)
2592*4882a593Smuzhiyun goto out_put;
2593*4882a593Smuzhiyun
2594*4882a593Smuzhiyun if (filename_len > (size_t)remaining_space) {
2595*4882a593Smuzhiyun filename += filename_len - remaining_space;
2596*4882a593Smuzhiyun filename_len = remaining_space;
2597*4882a593Smuzhiyun }
2598*4882a593Smuzhiyun
2599*4882a593Smuzhiyun to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2600*4882a593Smuzhiyun pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2601*4882a593Smuzhiyun memmove(pos + filename_len, pos, to_move);
2602*4882a593Smuzhiyun memcpy(pos, filename, filename_len);
2603*4882a593Smuzhiyun
2604*4882a593Smuzhiyun ttrace->filename.ptr = 0;
2605*4882a593Smuzhiyun ttrace->filename.entry_str_pos = 0;
2606*4882a593Smuzhiyun out_put:
2607*4882a593Smuzhiyun thread__put(thread);
2608*4882a593Smuzhiyun out:
2609*4882a593Smuzhiyun return 0;
2610*4882a593Smuzhiyun }
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun static int trace__sched_stat_runtime(struct trace *trace, struct evsel *evsel,
2613*4882a593Smuzhiyun union perf_event *event __maybe_unused,
2614*4882a593Smuzhiyun struct perf_sample *sample)
2615*4882a593Smuzhiyun {
2616*4882a593Smuzhiyun u64 runtime = evsel__intval(evsel, sample, "runtime");
2617*4882a593Smuzhiyun double runtime_ms = (double)runtime / NSEC_PER_MSEC;
2618*4882a593Smuzhiyun struct thread *thread = machine__findnew_thread(trace->host,
2619*4882a593Smuzhiyun sample->pid,
2620*4882a593Smuzhiyun sample->tid);
2621*4882a593Smuzhiyun struct thread_trace *ttrace = thread__trace(thread, trace->output);
2622*4882a593Smuzhiyun
2623*4882a593Smuzhiyun if (ttrace == NULL)
2624*4882a593Smuzhiyun goto out_dump;
2625*4882a593Smuzhiyun
2626*4882a593Smuzhiyun ttrace->runtime_ms += runtime_ms;
2627*4882a593Smuzhiyun trace->runtime_ms += runtime_ms;
2628*4882a593Smuzhiyun out_put:
2629*4882a593Smuzhiyun thread__put(thread);
2630*4882a593Smuzhiyun return 0;
2631*4882a593Smuzhiyun
2632*4882a593Smuzhiyun out_dump:
2633*4882a593Smuzhiyun fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
2634*4882a593Smuzhiyun evsel->name,
2635*4882a593Smuzhiyun evsel__strval(evsel, sample, "comm"),
2636*4882a593Smuzhiyun (pid_t)evsel__intval(evsel, sample, "pid"),
2637*4882a593Smuzhiyun runtime,
2638*4882a593Smuzhiyun evsel__intval(evsel, sample, "vruntime"));
2639*4882a593Smuzhiyun goto out_put;
2640*4882a593Smuzhiyun }
2641*4882a593Smuzhiyun
2642*4882a593Smuzhiyun static int bpf_output__printer(enum binary_printer_ops op,
2643*4882a593Smuzhiyun unsigned int val, void *extra __maybe_unused, FILE *fp)
2644*4882a593Smuzhiyun {
2645*4882a593Smuzhiyun unsigned char ch = (unsigned char)val;
2646*4882a593Smuzhiyun
2647*4882a593Smuzhiyun switch (op) {
2648*4882a593Smuzhiyun case BINARY_PRINT_CHAR_DATA:
2649*4882a593Smuzhiyun return fprintf(fp, "%c", isprint(ch) ? ch : '.');
2650*4882a593Smuzhiyun case BINARY_PRINT_DATA_BEGIN:
2651*4882a593Smuzhiyun case BINARY_PRINT_LINE_BEGIN:
2652*4882a593Smuzhiyun case BINARY_PRINT_ADDR:
2653*4882a593Smuzhiyun case BINARY_PRINT_NUM_DATA:
2654*4882a593Smuzhiyun case BINARY_PRINT_NUM_PAD:
2655*4882a593Smuzhiyun case BINARY_PRINT_SEP:
2656*4882a593Smuzhiyun case BINARY_PRINT_CHAR_PAD:
2657*4882a593Smuzhiyun case BINARY_PRINT_LINE_END:
2658*4882a593Smuzhiyun case BINARY_PRINT_DATA_END:
2659*4882a593Smuzhiyun default:
2660*4882a593Smuzhiyun break;
2661*4882a593Smuzhiyun }
2662*4882a593Smuzhiyun
2663*4882a593Smuzhiyun return 0;
2664*4882a593Smuzhiyun }
2665*4882a593Smuzhiyun
2666*4882a593Smuzhiyun static void bpf_output__fprintf(struct trace *trace,
2667*4882a593Smuzhiyun struct perf_sample *sample)
2668*4882a593Smuzhiyun {
2669*4882a593Smuzhiyun binary__fprintf(sample->raw_data, sample->raw_size, 8,
2670*4882a593Smuzhiyun bpf_output__printer, NULL, trace->output);
2671*4882a593Smuzhiyun ++trace->nr_events_printed;
2672*4882a593Smuzhiyun }
2673*4882a593Smuzhiyun
2674*4882a593Smuzhiyun static size_t trace__fprintf_tp_fields(struct trace *trace, struct evsel *evsel, struct perf_sample *sample,
2675*4882a593Smuzhiyun struct thread *thread, void *augmented_args, int augmented_args_size)
2676*4882a593Smuzhiyun {
2677*4882a593Smuzhiyun char bf[2048];
2678*4882a593Smuzhiyun size_t size = sizeof(bf);
2679*4882a593Smuzhiyun struct tep_format_field *field = evsel->tp_format->format.fields;
2680*4882a593Smuzhiyun struct syscall_arg_fmt *arg = __evsel__syscall_arg_fmt(evsel);
2681*4882a593Smuzhiyun size_t printed = 0;
2682*4882a593Smuzhiyun unsigned long val;
2683*4882a593Smuzhiyun u8 bit = 1;
2684*4882a593Smuzhiyun struct syscall_arg syscall_arg = {
2685*4882a593Smuzhiyun .augmented = {
2686*4882a593Smuzhiyun .size = augmented_args_size,
2687*4882a593Smuzhiyun .args = augmented_args,
2688*4882a593Smuzhiyun },
2689*4882a593Smuzhiyun .idx = 0,
2690*4882a593Smuzhiyun .mask = 0,
2691*4882a593Smuzhiyun .trace = trace,
2692*4882a593Smuzhiyun .thread = thread,
2693*4882a593Smuzhiyun .show_string_prefix = trace->show_string_prefix,
2694*4882a593Smuzhiyun };
2695*4882a593Smuzhiyun
2696*4882a593Smuzhiyun for (; field && arg; field = field->next, ++syscall_arg.idx, bit <<= 1, ++arg) {
2697*4882a593Smuzhiyun if (syscall_arg.mask & bit)
2698*4882a593Smuzhiyun continue;
2699*4882a593Smuzhiyun
2700*4882a593Smuzhiyun syscall_arg.len = 0;
2701*4882a593Smuzhiyun syscall_arg.fmt = arg;
2702*4882a593Smuzhiyun if (field->flags & TEP_FIELD_IS_ARRAY) {
2703*4882a593Smuzhiyun int offset = field->offset;
2704*4882a593Smuzhiyun
2705*4882a593Smuzhiyun if (field->flags & TEP_FIELD_IS_DYNAMIC) {
2706*4882a593Smuzhiyun offset = format_field__intval(field, sample, evsel->needs_swap);
2707*4882a593Smuzhiyun syscall_arg.len = offset >> 16;
2708*4882a593Smuzhiyun offset &= 0xffff;
2709*4882a593Smuzhiyun }
2710*4882a593Smuzhiyun
2711*4882a593Smuzhiyun val = (uintptr_t)(sample->raw_data + offset);
2712*4882a593Smuzhiyun } else
2713*4882a593Smuzhiyun val = format_field__intval(field, sample, evsel->needs_swap);
2714*4882a593Smuzhiyun /*
2715*4882a593Smuzhiyun * Some syscall args need some mask, most don't and
2716*4882a593Smuzhiyun * return val untouched.
2717*4882a593Smuzhiyun */
2718*4882a593Smuzhiyun val = syscall_arg_fmt__mask_val(arg, &syscall_arg, val);
2719*4882a593Smuzhiyun
2720*4882a593Smuzhiyun /*
2721*4882a593Smuzhiyun * Suppress this argument if its value is zero and
2722*4882a593Smuzhiyun * and we don't have a string associated in an
2723*4882a593Smuzhiyun * strarray for it.
2724*4882a593Smuzhiyun */
2725*4882a593Smuzhiyun if (val == 0 &&
2726*4882a593Smuzhiyun !trace->show_zeros &&
2727*4882a593Smuzhiyun !((arg->show_zero ||
2728*4882a593Smuzhiyun arg->scnprintf == SCA_STRARRAY ||
2729*4882a593Smuzhiyun arg->scnprintf == SCA_STRARRAYS) &&
2730*4882a593Smuzhiyun arg->parm))
2731*4882a593Smuzhiyun continue;
2732*4882a593Smuzhiyun
2733*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : "");
2734*4882a593Smuzhiyun
2735*4882a593Smuzhiyun /*
2736*4882a593Smuzhiyun * XXX Perhaps we should have a show_tp_arg_names,
2737*4882a593Smuzhiyun * leaving show_arg_names just for syscalls?
2738*4882a593Smuzhiyun */
2739*4882a593Smuzhiyun if (1 || trace->show_arg_names)
2740*4882a593Smuzhiyun printed += scnprintf(bf + printed, size - printed, "%s: ", field->name);
2741*4882a593Smuzhiyun
2742*4882a593Smuzhiyun printed += syscall_arg_fmt__scnprintf_val(arg, bf + printed, size - printed, &syscall_arg, val);
2743*4882a593Smuzhiyun }
2744*4882a593Smuzhiyun
2745*4882a593Smuzhiyun return printed + fprintf(trace->output, "%s", bf);
2746*4882a593Smuzhiyun }
2747*4882a593Smuzhiyun
2748*4882a593Smuzhiyun static int trace__event_handler(struct trace *trace, struct evsel *evsel,
2749*4882a593Smuzhiyun union perf_event *event __maybe_unused,
2750*4882a593Smuzhiyun struct perf_sample *sample)
2751*4882a593Smuzhiyun {
2752*4882a593Smuzhiyun struct thread *thread;
2753*4882a593Smuzhiyun int callchain_ret = 0;
2754*4882a593Smuzhiyun /*
2755*4882a593Smuzhiyun * Check if we called perf_evsel__disable(evsel) due to, for instance,
2756*4882a593Smuzhiyun * this event's max_events having been hit and this is an entry coming
2757*4882a593Smuzhiyun * from the ring buffer that we should discard, since the max events
2758*4882a593Smuzhiyun * have already been considered/printed.
2759*4882a593Smuzhiyun */
2760*4882a593Smuzhiyun if (evsel->disabled)
2761*4882a593Smuzhiyun return 0;
2762*4882a593Smuzhiyun
2763*4882a593Smuzhiyun thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2764*4882a593Smuzhiyun
2765*4882a593Smuzhiyun if (sample->callchain) {
2766*4882a593Smuzhiyun callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2767*4882a593Smuzhiyun if (callchain_ret == 0) {
2768*4882a593Smuzhiyun if (callchain_cursor.nr < trace->min_stack)
2769*4882a593Smuzhiyun goto out;
2770*4882a593Smuzhiyun callchain_ret = 1;
2771*4882a593Smuzhiyun }
2772*4882a593Smuzhiyun }
2773*4882a593Smuzhiyun
2774*4882a593Smuzhiyun trace__printf_interrupted_entry(trace);
2775*4882a593Smuzhiyun trace__fprintf_tstamp(trace, sample->time, trace->output);
2776*4882a593Smuzhiyun
2777*4882a593Smuzhiyun if (trace->trace_syscalls && trace->show_duration)
2778*4882a593Smuzhiyun fprintf(trace->output, "( ): ");
2779*4882a593Smuzhiyun
2780*4882a593Smuzhiyun if (thread)
2781*4882a593Smuzhiyun trace__fprintf_comm_tid(trace, thread, trace->output);
2782*4882a593Smuzhiyun
2783*4882a593Smuzhiyun if (evsel == trace->syscalls.events.augmented) {
2784*4882a593Smuzhiyun int id = perf_evsel__sc_tp_uint(evsel, id, sample);
2785*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, evsel, id);
2786*4882a593Smuzhiyun
2787*4882a593Smuzhiyun if (sc) {
2788*4882a593Smuzhiyun fprintf(trace->output, "%s(", sc->name);
2789*4882a593Smuzhiyun trace__fprintf_sys_enter(trace, evsel, sample);
2790*4882a593Smuzhiyun fputc(')', trace->output);
2791*4882a593Smuzhiyun goto newline;
2792*4882a593Smuzhiyun }
2793*4882a593Smuzhiyun
2794*4882a593Smuzhiyun /*
2795*4882a593Smuzhiyun * XXX: Not having the associated syscall info or not finding/adding
2796*4882a593Smuzhiyun * the thread should never happen, but if it does...
2797*4882a593Smuzhiyun * fall thru and print it as a bpf_output event.
2798*4882a593Smuzhiyun */
2799*4882a593Smuzhiyun }
2800*4882a593Smuzhiyun
2801*4882a593Smuzhiyun fprintf(trace->output, "%s(", evsel->name);
2802*4882a593Smuzhiyun
2803*4882a593Smuzhiyun if (evsel__is_bpf_output(evsel)) {
2804*4882a593Smuzhiyun bpf_output__fprintf(trace, sample);
2805*4882a593Smuzhiyun } else if (evsel->tp_format) {
2806*4882a593Smuzhiyun if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2807*4882a593Smuzhiyun trace__fprintf_sys_enter(trace, evsel, sample)) {
2808*4882a593Smuzhiyun if (trace->libtraceevent_print) {
2809*4882a593Smuzhiyun event_format__fprintf(evsel->tp_format, sample->cpu,
2810*4882a593Smuzhiyun sample->raw_data, sample->raw_size,
2811*4882a593Smuzhiyun trace->output);
2812*4882a593Smuzhiyun } else {
2813*4882a593Smuzhiyun trace__fprintf_tp_fields(trace, evsel, sample, thread, NULL, 0);
2814*4882a593Smuzhiyun }
2815*4882a593Smuzhiyun }
2816*4882a593Smuzhiyun }
2817*4882a593Smuzhiyun
2818*4882a593Smuzhiyun newline:
2819*4882a593Smuzhiyun fprintf(trace->output, ")\n");
2820*4882a593Smuzhiyun
2821*4882a593Smuzhiyun if (callchain_ret > 0)
2822*4882a593Smuzhiyun trace__fprintf_callchain(trace, sample);
2823*4882a593Smuzhiyun else if (callchain_ret < 0)
2824*4882a593Smuzhiyun pr_err("Problem processing %s callchain, skipping...\n", evsel__name(evsel));
2825*4882a593Smuzhiyun
2826*4882a593Smuzhiyun ++trace->nr_events_printed;
2827*4882a593Smuzhiyun
2828*4882a593Smuzhiyun if (evsel->max_events != ULONG_MAX && ++evsel->nr_events_printed == evsel->max_events) {
2829*4882a593Smuzhiyun evsel__disable(evsel);
2830*4882a593Smuzhiyun evsel__close(evsel);
2831*4882a593Smuzhiyun }
2832*4882a593Smuzhiyun out:
2833*4882a593Smuzhiyun thread__put(thread);
2834*4882a593Smuzhiyun return 0;
2835*4882a593Smuzhiyun }
2836*4882a593Smuzhiyun
2837*4882a593Smuzhiyun static void print_location(FILE *f, struct perf_sample *sample,
2838*4882a593Smuzhiyun struct addr_location *al,
2839*4882a593Smuzhiyun bool print_dso, bool print_sym)
2840*4882a593Smuzhiyun {
2841*4882a593Smuzhiyun
2842*4882a593Smuzhiyun if ((verbose > 0 || print_dso) && al->map)
2843*4882a593Smuzhiyun fprintf(f, "%s@", al->map->dso->long_name);
2844*4882a593Smuzhiyun
2845*4882a593Smuzhiyun if ((verbose > 0 || print_sym) && al->sym)
2846*4882a593Smuzhiyun fprintf(f, "%s+0x%" PRIx64, al->sym->name,
2847*4882a593Smuzhiyun al->addr - al->sym->start);
2848*4882a593Smuzhiyun else if (al->map)
2849*4882a593Smuzhiyun fprintf(f, "0x%" PRIx64, al->addr);
2850*4882a593Smuzhiyun else
2851*4882a593Smuzhiyun fprintf(f, "0x%" PRIx64, sample->addr);
2852*4882a593Smuzhiyun }
2853*4882a593Smuzhiyun
2854*4882a593Smuzhiyun static int trace__pgfault(struct trace *trace,
2855*4882a593Smuzhiyun struct evsel *evsel,
2856*4882a593Smuzhiyun union perf_event *event __maybe_unused,
2857*4882a593Smuzhiyun struct perf_sample *sample)
2858*4882a593Smuzhiyun {
2859*4882a593Smuzhiyun struct thread *thread;
2860*4882a593Smuzhiyun struct addr_location al;
2861*4882a593Smuzhiyun char map_type = 'd';
2862*4882a593Smuzhiyun struct thread_trace *ttrace;
2863*4882a593Smuzhiyun int err = -1;
2864*4882a593Smuzhiyun int callchain_ret = 0;
2865*4882a593Smuzhiyun
2866*4882a593Smuzhiyun thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2867*4882a593Smuzhiyun
2868*4882a593Smuzhiyun if (sample->callchain) {
2869*4882a593Smuzhiyun callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2870*4882a593Smuzhiyun if (callchain_ret == 0) {
2871*4882a593Smuzhiyun if (callchain_cursor.nr < trace->min_stack)
2872*4882a593Smuzhiyun goto out_put;
2873*4882a593Smuzhiyun callchain_ret = 1;
2874*4882a593Smuzhiyun }
2875*4882a593Smuzhiyun }
2876*4882a593Smuzhiyun
2877*4882a593Smuzhiyun ttrace = thread__trace(thread, trace->output);
2878*4882a593Smuzhiyun if (ttrace == NULL)
2879*4882a593Smuzhiyun goto out_put;
2880*4882a593Smuzhiyun
2881*4882a593Smuzhiyun if (evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2882*4882a593Smuzhiyun ttrace->pfmaj++;
2883*4882a593Smuzhiyun else
2884*4882a593Smuzhiyun ttrace->pfmin++;
2885*4882a593Smuzhiyun
2886*4882a593Smuzhiyun if (trace->summary_only)
2887*4882a593Smuzhiyun goto out;
2888*4882a593Smuzhiyun
2889*4882a593Smuzhiyun thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
2890*4882a593Smuzhiyun
2891*4882a593Smuzhiyun trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
2892*4882a593Smuzhiyun
2893*4882a593Smuzhiyun fprintf(trace->output, "%sfault [",
2894*4882a593Smuzhiyun evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2895*4882a593Smuzhiyun "maj" : "min");
2896*4882a593Smuzhiyun
2897*4882a593Smuzhiyun print_location(trace->output, sample, &al, false, true);
2898*4882a593Smuzhiyun
2899*4882a593Smuzhiyun fprintf(trace->output, "] => ");
2900*4882a593Smuzhiyun
2901*4882a593Smuzhiyun thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
2902*4882a593Smuzhiyun
2903*4882a593Smuzhiyun if (!al.map) {
2904*4882a593Smuzhiyun thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
2905*4882a593Smuzhiyun
2906*4882a593Smuzhiyun if (al.map)
2907*4882a593Smuzhiyun map_type = 'x';
2908*4882a593Smuzhiyun else
2909*4882a593Smuzhiyun map_type = '?';
2910*4882a593Smuzhiyun }
2911*4882a593Smuzhiyun
2912*4882a593Smuzhiyun print_location(trace->output, sample, &al, true, false);
2913*4882a593Smuzhiyun
2914*4882a593Smuzhiyun fprintf(trace->output, " (%c%c)\n", map_type, al.level);
2915*4882a593Smuzhiyun
2916*4882a593Smuzhiyun if (callchain_ret > 0)
2917*4882a593Smuzhiyun trace__fprintf_callchain(trace, sample);
2918*4882a593Smuzhiyun else if (callchain_ret < 0)
2919*4882a593Smuzhiyun pr_err("Problem processing %s callchain, skipping...\n", evsel__name(evsel));
2920*4882a593Smuzhiyun
2921*4882a593Smuzhiyun ++trace->nr_events_printed;
2922*4882a593Smuzhiyun out:
2923*4882a593Smuzhiyun err = 0;
2924*4882a593Smuzhiyun out_put:
2925*4882a593Smuzhiyun thread__put(thread);
2926*4882a593Smuzhiyun return err;
2927*4882a593Smuzhiyun }
2928*4882a593Smuzhiyun
2929*4882a593Smuzhiyun static void trace__set_base_time(struct trace *trace,
2930*4882a593Smuzhiyun struct evsel *evsel,
2931*4882a593Smuzhiyun struct perf_sample *sample)
2932*4882a593Smuzhiyun {
2933*4882a593Smuzhiyun /*
2934*4882a593Smuzhiyun * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2935*4882a593Smuzhiyun * and don't use sample->time unconditionally, we may end up having
2936*4882a593Smuzhiyun * some other event in the future without PERF_SAMPLE_TIME for good
2937*4882a593Smuzhiyun * reason, i.e. we may not be interested in its timestamps, just in
2938*4882a593Smuzhiyun * it taking place, picking some piece of information when it
2939*4882a593Smuzhiyun * appears in our event stream (vfs_getname comes to mind).
2940*4882a593Smuzhiyun */
2941*4882a593Smuzhiyun if (trace->base_time == 0 && !trace->full_time &&
2942*4882a593Smuzhiyun (evsel->core.attr.sample_type & PERF_SAMPLE_TIME))
2943*4882a593Smuzhiyun trace->base_time = sample->time;
2944*4882a593Smuzhiyun }
2945*4882a593Smuzhiyun
2946*4882a593Smuzhiyun static int trace__process_sample(struct perf_tool *tool,
2947*4882a593Smuzhiyun union perf_event *event,
2948*4882a593Smuzhiyun struct perf_sample *sample,
2949*4882a593Smuzhiyun struct evsel *evsel,
2950*4882a593Smuzhiyun struct machine *machine __maybe_unused)
2951*4882a593Smuzhiyun {
2952*4882a593Smuzhiyun struct trace *trace = container_of(tool, struct trace, tool);
2953*4882a593Smuzhiyun struct thread *thread;
2954*4882a593Smuzhiyun int err = 0;
2955*4882a593Smuzhiyun
2956*4882a593Smuzhiyun tracepoint_handler handler = evsel->handler;
2957*4882a593Smuzhiyun
2958*4882a593Smuzhiyun thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2959*4882a593Smuzhiyun if (thread && thread__is_filtered(thread))
2960*4882a593Smuzhiyun goto out;
2961*4882a593Smuzhiyun
2962*4882a593Smuzhiyun trace__set_base_time(trace, evsel, sample);
2963*4882a593Smuzhiyun
2964*4882a593Smuzhiyun if (handler) {
2965*4882a593Smuzhiyun ++trace->nr_events;
2966*4882a593Smuzhiyun handler(trace, evsel, event, sample);
2967*4882a593Smuzhiyun }
2968*4882a593Smuzhiyun out:
2969*4882a593Smuzhiyun thread__put(thread);
2970*4882a593Smuzhiyun return err;
2971*4882a593Smuzhiyun }
2972*4882a593Smuzhiyun
2973*4882a593Smuzhiyun static int trace__record(struct trace *trace, int argc, const char **argv)
2974*4882a593Smuzhiyun {
2975*4882a593Smuzhiyun unsigned int rec_argc, i, j;
2976*4882a593Smuzhiyun const char **rec_argv;
2977*4882a593Smuzhiyun const char * const record_args[] = {
2978*4882a593Smuzhiyun "record",
2979*4882a593Smuzhiyun "-R",
2980*4882a593Smuzhiyun "-m", "1024",
2981*4882a593Smuzhiyun "-c", "1",
2982*4882a593Smuzhiyun };
2983*4882a593Smuzhiyun pid_t pid = getpid();
2984*4882a593Smuzhiyun char *filter = asprintf__tp_filter_pids(1, &pid);
2985*4882a593Smuzhiyun const char * const sc_args[] = { "-e", };
2986*4882a593Smuzhiyun unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2987*4882a593Smuzhiyun const char * const majpf_args[] = { "-e", "major-faults" };
2988*4882a593Smuzhiyun unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2989*4882a593Smuzhiyun const char * const minpf_args[] = { "-e", "minor-faults" };
2990*4882a593Smuzhiyun unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2991*4882a593Smuzhiyun int err = -1;
2992*4882a593Smuzhiyun
2993*4882a593Smuzhiyun /* +3 is for the event string below and the pid filter */
2994*4882a593Smuzhiyun rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 3 +
2995*4882a593Smuzhiyun majpf_args_nr + minpf_args_nr + argc;
2996*4882a593Smuzhiyun rec_argv = calloc(rec_argc + 1, sizeof(char *));
2997*4882a593Smuzhiyun
2998*4882a593Smuzhiyun if (rec_argv == NULL || filter == NULL)
2999*4882a593Smuzhiyun goto out_free;
3000*4882a593Smuzhiyun
3001*4882a593Smuzhiyun j = 0;
3002*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(record_args); i++)
3003*4882a593Smuzhiyun rec_argv[j++] = record_args[i];
3004*4882a593Smuzhiyun
3005*4882a593Smuzhiyun if (trace->trace_syscalls) {
3006*4882a593Smuzhiyun for (i = 0; i < sc_args_nr; i++)
3007*4882a593Smuzhiyun rec_argv[j++] = sc_args[i];
3008*4882a593Smuzhiyun
3009*4882a593Smuzhiyun /* event string may be different for older kernels - e.g., RHEL6 */
3010*4882a593Smuzhiyun if (is_valid_tracepoint("raw_syscalls:sys_enter"))
3011*4882a593Smuzhiyun rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
3012*4882a593Smuzhiyun else if (is_valid_tracepoint("syscalls:sys_enter"))
3013*4882a593Smuzhiyun rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
3014*4882a593Smuzhiyun else {
3015*4882a593Smuzhiyun pr_err("Neither raw_syscalls nor syscalls events exist.\n");
3016*4882a593Smuzhiyun goto out_free;
3017*4882a593Smuzhiyun }
3018*4882a593Smuzhiyun }
3019*4882a593Smuzhiyun
3020*4882a593Smuzhiyun rec_argv[j++] = "--filter";
3021*4882a593Smuzhiyun rec_argv[j++] = filter;
3022*4882a593Smuzhiyun
3023*4882a593Smuzhiyun if (trace->trace_pgfaults & TRACE_PFMAJ)
3024*4882a593Smuzhiyun for (i = 0; i < majpf_args_nr; i++)
3025*4882a593Smuzhiyun rec_argv[j++] = majpf_args[i];
3026*4882a593Smuzhiyun
3027*4882a593Smuzhiyun if (trace->trace_pgfaults & TRACE_PFMIN)
3028*4882a593Smuzhiyun for (i = 0; i < minpf_args_nr; i++)
3029*4882a593Smuzhiyun rec_argv[j++] = minpf_args[i];
3030*4882a593Smuzhiyun
3031*4882a593Smuzhiyun for (i = 0; i < (unsigned int)argc; i++)
3032*4882a593Smuzhiyun rec_argv[j++] = argv[i];
3033*4882a593Smuzhiyun
3034*4882a593Smuzhiyun err = cmd_record(j, rec_argv);
3035*4882a593Smuzhiyun out_free:
3036*4882a593Smuzhiyun free(filter);
3037*4882a593Smuzhiyun free(rec_argv);
3038*4882a593Smuzhiyun return err;
3039*4882a593Smuzhiyun }
3040*4882a593Smuzhiyun
3041*4882a593Smuzhiyun static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
3042*4882a593Smuzhiyun
3043*4882a593Smuzhiyun static bool evlist__add_vfs_getname(struct evlist *evlist)
3044*4882a593Smuzhiyun {
3045*4882a593Smuzhiyun bool found = false;
3046*4882a593Smuzhiyun struct evsel *evsel, *tmp;
3047*4882a593Smuzhiyun struct parse_events_error err;
3048*4882a593Smuzhiyun int ret;
3049*4882a593Smuzhiyun
3050*4882a593Smuzhiyun bzero(&err, sizeof(err));
3051*4882a593Smuzhiyun ret = parse_events(evlist, "probe:vfs_getname*", &err);
3052*4882a593Smuzhiyun if (ret) {
3053*4882a593Smuzhiyun free(err.str);
3054*4882a593Smuzhiyun free(err.help);
3055*4882a593Smuzhiyun free(err.first_str);
3056*4882a593Smuzhiyun free(err.first_help);
3057*4882a593Smuzhiyun return false;
3058*4882a593Smuzhiyun }
3059*4882a593Smuzhiyun
3060*4882a593Smuzhiyun evlist__for_each_entry_safe(evlist, evsel, tmp) {
3061*4882a593Smuzhiyun if (!strstarts(evsel__name(evsel), "probe:vfs_getname"))
3062*4882a593Smuzhiyun continue;
3063*4882a593Smuzhiyun
3064*4882a593Smuzhiyun if (evsel__field(evsel, "pathname")) {
3065*4882a593Smuzhiyun evsel->handler = trace__vfs_getname;
3066*4882a593Smuzhiyun found = true;
3067*4882a593Smuzhiyun continue;
3068*4882a593Smuzhiyun }
3069*4882a593Smuzhiyun
3070*4882a593Smuzhiyun list_del_init(&evsel->core.node);
3071*4882a593Smuzhiyun evsel->evlist = NULL;
3072*4882a593Smuzhiyun evsel__delete(evsel);
3073*4882a593Smuzhiyun }
3074*4882a593Smuzhiyun
3075*4882a593Smuzhiyun return found;
3076*4882a593Smuzhiyun }
3077*4882a593Smuzhiyun
3078*4882a593Smuzhiyun static struct evsel *evsel__new_pgfault(u64 config)
3079*4882a593Smuzhiyun {
3080*4882a593Smuzhiyun struct evsel *evsel;
3081*4882a593Smuzhiyun struct perf_event_attr attr = {
3082*4882a593Smuzhiyun .type = PERF_TYPE_SOFTWARE,
3083*4882a593Smuzhiyun .mmap_data = 1,
3084*4882a593Smuzhiyun };
3085*4882a593Smuzhiyun
3086*4882a593Smuzhiyun attr.config = config;
3087*4882a593Smuzhiyun attr.sample_period = 1;
3088*4882a593Smuzhiyun
3089*4882a593Smuzhiyun event_attr_init(&attr);
3090*4882a593Smuzhiyun
3091*4882a593Smuzhiyun evsel = evsel__new(&attr);
3092*4882a593Smuzhiyun if (evsel)
3093*4882a593Smuzhiyun evsel->handler = trace__pgfault;
3094*4882a593Smuzhiyun
3095*4882a593Smuzhiyun return evsel;
3096*4882a593Smuzhiyun }
3097*4882a593Smuzhiyun
3098*4882a593Smuzhiyun static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
3099*4882a593Smuzhiyun {
3100*4882a593Smuzhiyun const u32 type = event->header.type;
3101*4882a593Smuzhiyun struct evsel *evsel;
3102*4882a593Smuzhiyun
3103*4882a593Smuzhiyun if (type != PERF_RECORD_SAMPLE) {
3104*4882a593Smuzhiyun trace__process_event(trace, trace->host, event, sample);
3105*4882a593Smuzhiyun return;
3106*4882a593Smuzhiyun }
3107*4882a593Smuzhiyun
3108*4882a593Smuzhiyun evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
3109*4882a593Smuzhiyun if (evsel == NULL) {
3110*4882a593Smuzhiyun fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
3111*4882a593Smuzhiyun return;
3112*4882a593Smuzhiyun }
3113*4882a593Smuzhiyun
3114*4882a593Smuzhiyun if (evswitch__discard(&trace->evswitch, evsel))
3115*4882a593Smuzhiyun return;
3116*4882a593Smuzhiyun
3117*4882a593Smuzhiyun trace__set_base_time(trace, evsel, sample);
3118*4882a593Smuzhiyun
3119*4882a593Smuzhiyun if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT &&
3120*4882a593Smuzhiyun sample->raw_data == NULL) {
3121*4882a593Smuzhiyun fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
3122*4882a593Smuzhiyun evsel__name(evsel), sample->tid,
3123*4882a593Smuzhiyun sample->cpu, sample->raw_size);
3124*4882a593Smuzhiyun } else {
3125*4882a593Smuzhiyun tracepoint_handler handler = evsel->handler;
3126*4882a593Smuzhiyun handler(trace, evsel, event, sample);
3127*4882a593Smuzhiyun }
3128*4882a593Smuzhiyun
3129*4882a593Smuzhiyun if (trace->nr_events_printed >= trace->max_events && trace->max_events != ULONG_MAX)
3130*4882a593Smuzhiyun interrupted = true;
3131*4882a593Smuzhiyun }
3132*4882a593Smuzhiyun
3133*4882a593Smuzhiyun static int trace__add_syscall_newtp(struct trace *trace)
3134*4882a593Smuzhiyun {
3135*4882a593Smuzhiyun int ret = -1;
3136*4882a593Smuzhiyun struct evlist *evlist = trace->evlist;
3137*4882a593Smuzhiyun struct evsel *sys_enter, *sys_exit;
3138*4882a593Smuzhiyun
3139*4882a593Smuzhiyun sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
3140*4882a593Smuzhiyun if (sys_enter == NULL)
3141*4882a593Smuzhiyun goto out;
3142*4882a593Smuzhiyun
3143*4882a593Smuzhiyun if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
3144*4882a593Smuzhiyun goto out_delete_sys_enter;
3145*4882a593Smuzhiyun
3146*4882a593Smuzhiyun sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
3147*4882a593Smuzhiyun if (sys_exit == NULL)
3148*4882a593Smuzhiyun goto out_delete_sys_enter;
3149*4882a593Smuzhiyun
3150*4882a593Smuzhiyun if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
3151*4882a593Smuzhiyun goto out_delete_sys_exit;
3152*4882a593Smuzhiyun
3153*4882a593Smuzhiyun evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
3154*4882a593Smuzhiyun evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
3155*4882a593Smuzhiyun
3156*4882a593Smuzhiyun evlist__add(evlist, sys_enter);
3157*4882a593Smuzhiyun evlist__add(evlist, sys_exit);
3158*4882a593Smuzhiyun
3159*4882a593Smuzhiyun if (callchain_param.enabled && !trace->kernel_syscallchains) {
3160*4882a593Smuzhiyun /*
3161*4882a593Smuzhiyun * We're interested only in the user space callchain
3162*4882a593Smuzhiyun * leading to the syscall, allow overriding that for
3163*4882a593Smuzhiyun * debugging reasons using --kernel_syscall_callchains
3164*4882a593Smuzhiyun */
3165*4882a593Smuzhiyun sys_exit->core.attr.exclude_callchain_kernel = 1;
3166*4882a593Smuzhiyun }
3167*4882a593Smuzhiyun
3168*4882a593Smuzhiyun trace->syscalls.events.sys_enter = sys_enter;
3169*4882a593Smuzhiyun trace->syscalls.events.sys_exit = sys_exit;
3170*4882a593Smuzhiyun
3171*4882a593Smuzhiyun ret = 0;
3172*4882a593Smuzhiyun out:
3173*4882a593Smuzhiyun return ret;
3174*4882a593Smuzhiyun
3175*4882a593Smuzhiyun out_delete_sys_exit:
3176*4882a593Smuzhiyun evsel__delete_priv(sys_exit);
3177*4882a593Smuzhiyun out_delete_sys_enter:
3178*4882a593Smuzhiyun evsel__delete_priv(sys_enter);
3179*4882a593Smuzhiyun goto out;
3180*4882a593Smuzhiyun }
3181*4882a593Smuzhiyun
3182*4882a593Smuzhiyun static int trace__set_ev_qualifier_tp_filter(struct trace *trace)
3183*4882a593Smuzhiyun {
3184*4882a593Smuzhiyun int err = -1;
3185*4882a593Smuzhiyun struct evsel *sys_exit;
3186*4882a593Smuzhiyun char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
3187*4882a593Smuzhiyun trace->ev_qualifier_ids.nr,
3188*4882a593Smuzhiyun trace->ev_qualifier_ids.entries);
3189*4882a593Smuzhiyun
3190*4882a593Smuzhiyun if (filter == NULL)
3191*4882a593Smuzhiyun goto out_enomem;
3192*4882a593Smuzhiyun
3193*4882a593Smuzhiyun if (!evsel__append_tp_filter(trace->syscalls.events.sys_enter, filter)) {
3194*4882a593Smuzhiyun sys_exit = trace->syscalls.events.sys_exit;
3195*4882a593Smuzhiyun err = evsel__append_tp_filter(sys_exit, filter);
3196*4882a593Smuzhiyun }
3197*4882a593Smuzhiyun
3198*4882a593Smuzhiyun free(filter);
3199*4882a593Smuzhiyun out:
3200*4882a593Smuzhiyun return err;
3201*4882a593Smuzhiyun out_enomem:
3202*4882a593Smuzhiyun errno = ENOMEM;
3203*4882a593Smuzhiyun goto out;
3204*4882a593Smuzhiyun }
3205*4882a593Smuzhiyun
3206*4882a593Smuzhiyun #ifdef HAVE_LIBBPF_SUPPORT
3207*4882a593Smuzhiyun static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace, const char *name)
3208*4882a593Smuzhiyun {
3209*4882a593Smuzhiyun if (trace->bpf_obj == NULL)
3210*4882a593Smuzhiyun return NULL;
3211*4882a593Smuzhiyun
3212*4882a593Smuzhiyun return bpf_object__find_map_by_name(trace->bpf_obj, name);
3213*4882a593Smuzhiyun }
3214*4882a593Smuzhiyun
3215*4882a593Smuzhiyun static void trace__set_bpf_map_filtered_pids(struct trace *trace)
3216*4882a593Smuzhiyun {
3217*4882a593Smuzhiyun trace->filter_pids.map = trace__find_bpf_map_by_name(trace, "pids_filtered");
3218*4882a593Smuzhiyun }
3219*4882a593Smuzhiyun
3220*4882a593Smuzhiyun static void trace__set_bpf_map_syscalls(struct trace *trace)
3221*4882a593Smuzhiyun {
3222*4882a593Smuzhiyun trace->syscalls.map = trace__find_bpf_map_by_name(trace, "syscalls");
3223*4882a593Smuzhiyun trace->syscalls.prog_array.sys_enter = trace__find_bpf_map_by_name(trace, "syscalls_sys_enter");
3224*4882a593Smuzhiyun trace->syscalls.prog_array.sys_exit = trace__find_bpf_map_by_name(trace, "syscalls_sys_exit");
3225*4882a593Smuzhiyun }
3226*4882a593Smuzhiyun
3227*4882a593Smuzhiyun static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace, const char *name)
3228*4882a593Smuzhiyun {
3229*4882a593Smuzhiyun if (trace->bpf_obj == NULL)
3230*4882a593Smuzhiyun return NULL;
3231*4882a593Smuzhiyun
3232*4882a593Smuzhiyun return bpf_object__find_program_by_title(trace->bpf_obj, name);
3233*4882a593Smuzhiyun }
3234*4882a593Smuzhiyun
3235*4882a593Smuzhiyun static struct bpf_program *trace__find_syscall_bpf_prog(struct trace *trace, struct syscall *sc,
3236*4882a593Smuzhiyun const char *prog_name, const char *type)
3237*4882a593Smuzhiyun {
3238*4882a593Smuzhiyun struct bpf_program *prog;
3239*4882a593Smuzhiyun
3240*4882a593Smuzhiyun if (prog_name == NULL) {
3241*4882a593Smuzhiyun char default_prog_name[256];
3242*4882a593Smuzhiyun scnprintf(default_prog_name, sizeof(default_prog_name), "!syscalls:sys_%s_%s", type, sc->name);
3243*4882a593Smuzhiyun prog = trace__find_bpf_program_by_title(trace, default_prog_name);
3244*4882a593Smuzhiyun if (prog != NULL)
3245*4882a593Smuzhiyun goto out_found;
3246*4882a593Smuzhiyun if (sc->fmt && sc->fmt->alias) {
3247*4882a593Smuzhiyun scnprintf(default_prog_name, sizeof(default_prog_name), "!syscalls:sys_%s_%s", type, sc->fmt->alias);
3248*4882a593Smuzhiyun prog = trace__find_bpf_program_by_title(trace, default_prog_name);
3249*4882a593Smuzhiyun if (prog != NULL)
3250*4882a593Smuzhiyun goto out_found;
3251*4882a593Smuzhiyun }
3252*4882a593Smuzhiyun goto out_unaugmented;
3253*4882a593Smuzhiyun }
3254*4882a593Smuzhiyun
3255*4882a593Smuzhiyun prog = trace__find_bpf_program_by_title(trace, prog_name);
3256*4882a593Smuzhiyun
3257*4882a593Smuzhiyun if (prog != NULL) {
3258*4882a593Smuzhiyun out_found:
3259*4882a593Smuzhiyun return prog;
3260*4882a593Smuzhiyun }
3261*4882a593Smuzhiyun
3262*4882a593Smuzhiyun pr_debug("Couldn't find BPF prog \"%s\" to associate with syscalls:sys_%s_%s, not augmenting it\n",
3263*4882a593Smuzhiyun prog_name, type, sc->name);
3264*4882a593Smuzhiyun out_unaugmented:
3265*4882a593Smuzhiyun return trace->syscalls.unaugmented_prog;
3266*4882a593Smuzhiyun }
3267*4882a593Smuzhiyun
3268*4882a593Smuzhiyun static void trace__init_syscall_bpf_progs(struct trace *trace, int id)
3269*4882a593Smuzhiyun {
3270*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, NULL, id);
3271*4882a593Smuzhiyun
3272*4882a593Smuzhiyun if (sc == NULL)
3273*4882a593Smuzhiyun return;
3274*4882a593Smuzhiyun
3275*4882a593Smuzhiyun sc->bpf_prog.sys_enter = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_enter : NULL, "enter");
3276*4882a593Smuzhiyun sc->bpf_prog.sys_exit = trace__find_syscall_bpf_prog(trace, sc, sc->fmt ? sc->fmt->bpf_prog_name.sys_exit : NULL, "exit");
3277*4882a593Smuzhiyun }
3278*4882a593Smuzhiyun
3279*4882a593Smuzhiyun static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int id)
3280*4882a593Smuzhiyun {
3281*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, NULL, id);
3282*4882a593Smuzhiyun return sc ? bpf_program__fd(sc->bpf_prog.sys_enter) : bpf_program__fd(trace->syscalls.unaugmented_prog);
3283*4882a593Smuzhiyun }
3284*4882a593Smuzhiyun
3285*4882a593Smuzhiyun static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int id)
3286*4882a593Smuzhiyun {
3287*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, NULL, id);
3288*4882a593Smuzhiyun return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(trace->syscalls.unaugmented_prog);
3289*4882a593Smuzhiyun }
3290*4882a593Smuzhiyun
3291*4882a593Smuzhiyun static void trace__init_bpf_map_syscall_args(struct trace *trace, int id, struct bpf_map_syscall_entry *entry)
3292*4882a593Smuzhiyun {
3293*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, NULL, id);
3294*4882a593Smuzhiyun int arg = 0;
3295*4882a593Smuzhiyun
3296*4882a593Smuzhiyun if (sc == NULL)
3297*4882a593Smuzhiyun goto out;
3298*4882a593Smuzhiyun
3299*4882a593Smuzhiyun for (; arg < sc->nr_args; ++arg) {
3300*4882a593Smuzhiyun entry->string_args_len[arg] = 0;
3301*4882a593Smuzhiyun if (sc->arg_fmt[arg].scnprintf == SCA_FILENAME) {
3302*4882a593Smuzhiyun /* Should be set like strace -s strsize */
3303*4882a593Smuzhiyun entry->string_args_len[arg] = PATH_MAX;
3304*4882a593Smuzhiyun }
3305*4882a593Smuzhiyun }
3306*4882a593Smuzhiyun out:
3307*4882a593Smuzhiyun for (; arg < 6; ++arg)
3308*4882a593Smuzhiyun entry->string_args_len[arg] = 0;
3309*4882a593Smuzhiyun }
3310*4882a593Smuzhiyun static int trace__set_ev_qualifier_bpf_filter(struct trace *trace)
3311*4882a593Smuzhiyun {
3312*4882a593Smuzhiyun int fd = bpf_map__fd(trace->syscalls.map);
3313*4882a593Smuzhiyun struct bpf_map_syscall_entry value = {
3314*4882a593Smuzhiyun .enabled = !trace->not_ev_qualifier,
3315*4882a593Smuzhiyun };
3316*4882a593Smuzhiyun int err = 0;
3317*4882a593Smuzhiyun size_t i;
3318*4882a593Smuzhiyun
3319*4882a593Smuzhiyun for (i = 0; i < trace->ev_qualifier_ids.nr; ++i) {
3320*4882a593Smuzhiyun int key = trace->ev_qualifier_ids.entries[i];
3321*4882a593Smuzhiyun
3322*4882a593Smuzhiyun if (value.enabled) {
3323*4882a593Smuzhiyun trace__init_bpf_map_syscall_args(trace, key, &value);
3324*4882a593Smuzhiyun trace__init_syscall_bpf_progs(trace, key);
3325*4882a593Smuzhiyun }
3326*4882a593Smuzhiyun
3327*4882a593Smuzhiyun err = bpf_map_update_elem(fd, &key, &value, BPF_EXIST);
3328*4882a593Smuzhiyun if (err)
3329*4882a593Smuzhiyun break;
3330*4882a593Smuzhiyun }
3331*4882a593Smuzhiyun
3332*4882a593Smuzhiyun return err;
3333*4882a593Smuzhiyun }
3334*4882a593Smuzhiyun
3335*4882a593Smuzhiyun static int __trace__init_syscalls_bpf_map(struct trace *trace, bool enabled)
3336*4882a593Smuzhiyun {
3337*4882a593Smuzhiyun int fd = bpf_map__fd(trace->syscalls.map);
3338*4882a593Smuzhiyun struct bpf_map_syscall_entry value = {
3339*4882a593Smuzhiyun .enabled = enabled,
3340*4882a593Smuzhiyun };
3341*4882a593Smuzhiyun int err = 0, key;
3342*4882a593Smuzhiyun
3343*4882a593Smuzhiyun for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) {
3344*4882a593Smuzhiyun if (enabled)
3345*4882a593Smuzhiyun trace__init_bpf_map_syscall_args(trace, key, &value);
3346*4882a593Smuzhiyun
3347*4882a593Smuzhiyun err = bpf_map_update_elem(fd, &key, &value, BPF_ANY);
3348*4882a593Smuzhiyun if (err)
3349*4882a593Smuzhiyun break;
3350*4882a593Smuzhiyun }
3351*4882a593Smuzhiyun
3352*4882a593Smuzhiyun return err;
3353*4882a593Smuzhiyun }
3354*4882a593Smuzhiyun
3355*4882a593Smuzhiyun static int trace__init_syscalls_bpf_map(struct trace *trace)
3356*4882a593Smuzhiyun {
3357*4882a593Smuzhiyun bool enabled = true;
3358*4882a593Smuzhiyun
3359*4882a593Smuzhiyun if (trace->ev_qualifier_ids.nr)
3360*4882a593Smuzhiyun enabled = trace->not_ev_qualifier;
3361*4882a593Smuzhiyun
3362*4882a593Smuzhiyun return __trace__init_syscalls_bpf_map(trace, enabled);
3363*4882a593Smuzhiyun }
3364*4882a593Smuzhiyun
3365*4882a593Smuzhiyun static struct bpf_program *trace__find_usable_bpf_prog_entry(struct trace *trace, struct syscall *sc)
3366*4882a593Smuzhiyun {
3367*4882a593Smuzhiyun struct tep_format_field *field, *candidate_field;
3368*4882a593Smuzhiyun int id;
3369*4882a593Smuzhiyun
3370*4882a593Smuzhiyun /*
3371*4882a593Smuzhiyun * We're only interested in syscalls that have a pointer:
3372*4882a593Smuzhiyun */
3373*4882a593Smuzhiyun for (field = sc->args; field; field = field->next) {
3374*4882a593Smuzhiyun if (field->flags & TEP_FIELD_IS_POINTER)
3375*4882a593Smuzhiyun goto try_to_find_pair;
3376*4882a593Smuzhiyun }
3377*4882a593Smuzhiyun
3378*4882a593Smuzhiyun return NULL;
3379*4882a593Smuzhiyun
3380*4882a593Smuzhiyun try_to_find_pair:
3381*4882a593Smuzhiyun for (id = 0; id < trace->sctbl->syscalls.nr_entries; ++id) {
3382*4882a593Smuzhiyun struct syscall *pair = trace__syscall_info(trace, NULL, id);
3383*4882a593Smuzhiyun struct bpf_program *pair_prog;
3384*4882a593Smuzhiyun bool is_candidate = false;
3385*4882a593Smuzhiyun
3386*4882a593Smuzhiyun if (pair == NULL || pair == sc ||
3387*4882a593Smuzhiyun pair->bpf_prog.sys_enter == trace->syscalls.unaugmented_prog)
3388*4882a593Smuzhiyun continue;
3389*4882a593Smuzhiyun
3390*4882a593Smuzhiyun for (field = sc->args, candidate_field = pair->args;
3391*4882a593Smuzhiyun field && candidate_field; field = field->next, candidate_field = candidate_field->next) {
3392*4882a593Smuzhiyun bool is_pointer = field->flags & TEP_FIELD_IS_POINTER,
3393*4882a593Smuzhiyun candidate_is_pointer = candidate_field->flags & TEP_FIELD_IS_POINTER;
3394*4882a593Smuzhiyun
3395*4882a593Smuzhiyun if (is_pointer) {
3396*4882a593Smuzhiyun if (!candidate_is_pointer) {
3397*4882a593Smuzhiyun // The candidate just doesn't copies our pointer arg, might copy other pointers we want.
3398*4882a593Smuzhiyun continue;
3399*4882a593Smuzhiyun }
3400*4882a593Smuzhiyun } else {
3401*4882a593Smuzhiyun if (candidate_is_pointer) {
3402*4882a593Smuzhiyun // The candidate might copy a pointer we don't have, skip it.
3403*4882a593Smuzhiyun goto next_candidate;
3404*4882a593Smuzhiyun }
3405*4882a593Smuzhiyun continue;
3406*4882a593Smuzhiyun }
3407*4882a593Smuzhiyun
3408*4882a593Smuzhiyun if (strcmp(field->type, candidate_field->type))
3409*4882a593Smuzhiyun goto next_candidate;
3410*4882a593Smuzhiyun
3411*4882a593Smuzhiyun is_candidate = true;
3412*4882a593Smuzhiyun }
3413*4882a593Smuzhiyun
3414*4882a593Smuzhiyun if (!is_candidate)
3415*4882a593Smuzhiyun goto next_candidate;
3416*4882a593Smuzhiyun
3417*4882a593Smuzhiyun /*
3418*4882a593Smuzhiyun * Check if the tentative pair syscall augmenter has more pointers, if it has,
3419*4882a593Smuzhiyun * then it may be collecting that and we then can't use it, as it would collect
3420*4882a593Smuzhiyun * more than what is common to the two syscalls.
3421*4882a593Smuzhiyun */
3422*4882a593Smuzhiyun if (candidate_field) {
3423*4882a593Smuzhiyun for (candidate_field = candidate_field->next; candidate_field; candidate_field = candidate_field->next)
3424*4882a593Smuzhiyun if (candidate_field->flags & TEP_FIELD_IS_POINTER)
3425*4882a593Smuzhiyun goto next_candidate;
3426*4882a593Smuzhiyun }
3427*4882a593Smuzhiyun
3428*4882a593Smuzhiyun pair_prog = pair->bpf_prog.sys_enter;
3429*4882a593Smuzhiyun /*
3430*4882a593Smuzhiyun * If the pair isn't enabled, then its bpf_prog.sys_enter will not
3431*4882a593Smuzhiyun * have been searched for, so search it here and if it returns the
3432*4882a593Smuzhiyun * unaugmented one, then ignore it, otherwise we'll reuse that BPF
3433*4882a593Smuzhiyun * program for a filtered syscall on a non-filtered one.
3434*4882a593Smuzhiyun *
3435*4882a593Smuzhiyun * For instance, we have "!syscalls:sys_enter_renameat" and that is
3436*4882a593Smuzhiyun * useful for "renameat2".
3437*4882a593Smuzhiyun */
3438*4882a593Smuzhiyun if (pair_prog == NULL) {
3439*4882a593Smuzhiyun pair_prog = trace__find_syscall_bpf_prog(trace, pair, pair->fmt ? pair->fmt->bpf_prog_name.sys_enter : NULL, "enter");
3440*4882a593Smuzhiyun if (pair_prog == trace->syscalls.unaugmented_prog)
3441*4882a593Smuzhiyun goto next_candidate;
3442*4882a593Smuzhiyun }
3443*4882a593Smuzhiyun
3444*4882a593Smuzhiyun pr_debug("Reusing \"%s\" BPF sys_enter augmenter for \"%s\"\n", pair->name, sc->name);
3445*4882a593Smuzhiyun return pair_prog;
3446*4882a593Smuzhiyun next_candidate:
3447*4882a593Smuzhiyun continue;
3448*4882a593Smuzhiyun }
3449*4882a593Smuzhiyun
3450*4882a593Smuzhiyun return NULL;
3451*4882a593Smuzhiyun }
3452*4882a593Smuzhiyun
3453*4882a593Smuzhiyun static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace)
3454*4882a593Smuzhiyun {
3455*4882a593Smuzhiyun int map_enter_fd = bpf_map__fd(trace->syscalls.prog_array.sys_enter),
3456*4882a593Smuzhiyun map_exit_fd = bpf_map__fd(trace->syscalls.prog_array.sys_exit);
3457*4882a593Smuzhiyun int err = 0, key;
3458*4882a593Smuzhiyun
3459*4882a593Smuzhiyun for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) {
3460*4882a593Smuzhiyun int prog_fd;
3461*4882a593Smuzhiyun
3462*4882a593Smuzhiyun if (!trace__syscall_enabled(trace, key))
3463*4882a593Smuzhiyun continue;
3464*4882a593Smuzhiyun
3465*4882a593Smuzhiyun trace__init_syscall_bpf_progs(trace, key);
3466*4882a593Smuzhiyun
3467*4882a593Smuzhiyun // It'll get at least the "!raw_syscalls:unaugmented"
3468*4882a593Smuzhiyun prog_fd = trace__bpf_prog_sys_enter_fd(trace, key);
3469*4882a593Smuzhiyun err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY);
3470*4882a593Smuzhiyun if (err)
3471*4882a593Smuzhiyun break;
3472*4882a593Smuzhiyun prog_fd = trace__bpf_prog_sys_exit_fd(trace, key);
3473*4882a593Smuzhiyun err = bpf_map_update_elem(map_exit_fd, &key, &prog_fd, BPF_ANY);
3474*4882a593Smuzhiyun if (err)
3475*4882a593Smuzhiyun break;
3476*4882a593Smuzhiyun }
3477*4882a593Smuzhiyun
3478*4882a593Smuzhiyun /*
3479*4882a593Smuzhiyun * Now lets do a second pass looking for enabled syscalls without
3480*4882a593Smuzhiyun * an augmenter that have a signature that is a superset of another
3481*4882a593Smuzhiyun * syscall with an augmenter so that we can auto-reuse it.
3482*4882a593Smuzhiyun *
3483*4882a593Smuzhiyun * I.e. if we have an augmenter for the "open" syscall that has
3484*4882a593Smuzhiyun * this signature:
3485*4882a593Smuzhiyun *
3486*4882a593Smuzhiyun * int open(const char *pathname, int flags, mode_t mode);
3487*4882a593Smuzhiyun *
3488*4882a593Smuzhiyun * I.e. that will collect just the first string argument, then we
3489*4882a593Smuzhiyun * can reuse it for the 'creat' syscall, that has this signature:
3490*4882a593Smuzhiyun *
3491*4882a593Smuzhiyun * int creat(const char *pathname, mode_t mode);
3492*4882a593Smuzhiyun *
3493*4882a593Smuzhiyun * and for:
3494*4882a593Smuzhiyun *
3495*4882a593Smuzhiyun * int stat(const char *pathname, struct stat *statbuf);
3496*4882a593Smuzhiyun * int lstat(const char *pathname, struct stat *statbuf);
3497*4882a593Smuzhiyun *
3498*4882a593Smuzhiyun * Because the 'open' augmenter will collect the first arg as a string,
3499*4882a593Smuzhiyun * and leave alone all the other args, which already helps with
3500*4882a593Smuzhiyun * beautifying 'stat' and 'lstat''s pathname arg.
3501*4882a593Smuzhiyun *
3502*4882a593Smuzhiyun * Then, in time, when 'stat' gets an augmenter that collects both
3503*4882a593Smuzhiyun * first and second arg (this one on the raw_syscalls:sys_exit prog
3504*4882a593Smuzhiyun * array tail call, then that one will be used.
3505*4882a593Smuzhiyun */
3506*4882a593Smuzhiyun for (key = 0; key < trace->sctbl->syscalls.nr_entries; ++key) {
3507*4882a593Smuzhiyun struct syscall *sc = trace__syscall_info(trace, NULL, key);
3508*4882a593Smuzhiyun struct bpf_program *pair_prog;
3509*4882a593Smuzhiyun int prog_fd;
3510*4882a593Smuzhiyun
3511*4882a593Smuzhiyun if (sc == NULL || sc->bpf_prog.sys_enter == NULL)
3512*4882a593Smuzhiyun continue;
3513*4882a593Smuzhiyun
3514*4882a593Smuzhiyun /*
3515*4882a593Smuzhiyun * For now we're just reusing the sys_enter prog, and if it
3516*4882a593Smuzhiyun * already has an augmenter, we don't need to find one.
3517*4882a593Smuzhiyun */
3518*4882a593Smuzhiyun if (sc->bpf_prog.sys_enter != trace->syscalls.unaugmented_prog)
3519*4882a593Smuzhiyun continue;
3520*4882a593Smuzhiyun
3521*4882a593Smuzhiyun /*
3522*4882a593Smuzhiyun * Look at all the other syscalls for one that has a signature
3523*4882a593Smuzhiyun * that is close enough that we can share:
3524*4882a593Smuzhiyun */
3525*4882a593Smuzhiyun pair_prog = trace__find_usable_bpf_prog_entry(trace, sc);
3526*4882a593Smuzhiyun if (pair_prog == NULL)
3527*4882a593Smuzhiyun continue;
3528*4882a593Smuzhiyun
3529*4882a593Smuzhiyun sc->bpf_prog.sys_enter = pair_prog;
3530*4882a593Smuzhiyun
3531*4882a593Smuzhiyun /*
3532*4882a593Smuzhiyun * Update the BPF_MAP_TYPE_PROG_SHARED for raw_syscalls:sys_enter
3533*4882a593Smuzhiyun * with the fd for the program we're reusing:
3534*4882a593Smuzhiyun */
3535*4882a593Smuzhiyun prog_fd = bpf_program__fd(sc->bpf_prog.sys_enter);
3536*4882a593Smuzhiyun err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY);
3537*4882a593Smuzhiyun if (err)
3538*4882a593Smuzhiyun break;
3539*4882a593Smuzhiyun }
3540*4882a593Smuzhiyun
3541*4882a593Smuzhiyun
3542*4882a593Smuzhiyun return err;
3543*4882a593Smuzhiyun }
3544*4882a593Smuzhiyun
3545*4882a593Smuzhiyun static void trace__delete_augmented_syscalls(struct trace *trace)
3546*4882a593Smuzhiyun {
3547*4882a593Smuzhiyun struct evsel *evsel, *tmp;
3548*4882a593Smuzhiyun
3549*4882a593Smuzhiyun evlist__remove(trace->evlist, trace->syscalls.events.augmented);
3550*4882a593Smuzhiyun evsel__delete(trace->syscalls.events.augmented);
3551*4882a593Smuzhiyun trace->syscalls.events.augmented = NULL;
3552*4882a593Smuzhiyun
3553*4882a593Smuzhiyun evlist__for_each_entry_safe(trace->evlist, tmp, evsel) {
3554*4882a593Smuzhiyun if (evsel->bpf_obj == trace->bpf_obj) {
3555*4882a593Smuzhiyun evlist__remove(trace->evlist, evsel);
3556*4882a593Smuzhiyun evsel__delete(evsel);
3557*4882a593Smuzhiyun }
3558*4882a593Smuzhiyun
3559*4882a593Smuzhiyun }
3560*4882a593Smuzhiyun
3561*4882a593Smuzhiyun bpf_object__close(trace->bpf_obj);
3562*4882a593Smuzhiyun trace->bpf_obj = NULL;
3563*4882a593Smuzhiyun }
3564*4882a593Smuzhiyun #else // HAVE_LIBBPF_SUPPORT
3565*4882a593Smuzhiyun static struct bpf_map *trace__find_bpf_map_by_name(struct trace *trace __maybe_unused,
3566*4882a593Smuzhiyun const char *name __maybe_unused)
3567*4882a593Smuzhiyun {
3568*4882a593Smuzhiyun return NULL;
3569*4882a593Smuzhiyun }
3570*4882a593Smuzhiyun
3571*4882a593Smuzhiyun static void trace__set_bpf_map_filtered_pids(struct trace *trace __maybe_unused)
3572*4882a593Smuzhiyun {
3573*4882a593Smuzhiyun }
3574*4882a593Smuzhiyun
3575*4882a593Smuzhiyun static void trace__set_bpf_map_syscalls(struct trace *trace __maybe_unused)
3576*4882a593Smuzhiyun {
3577*4882a593Smuzhiyun }
3578*4882a593Smuzhiyun
3579*4882a593Smuzhiyun static int trace__set_ev_qualifier_bpf_filter(struct trace *trace __maybe_unused)
3580*4882a593Smuzhiyun {
3581*4882a593Smuzhiyun return 0;
3582*4882a593Smuzhiyun }
3583*4882a593Smuzhiyun
3584*4882a593Smuzhiyun static int trace__init_syscalls_bpf_map(struct trace *trace __maybe_unused)
3585*4882a593Smuzhiyun {
3586*4882a593Smuzhiyun return 0;
3587*4882a593Smuzhiyun }
3588*4882a593Smuzhiyun
3589*4882a593Smuzhiyun static struct bpf_program *trace__find_bpf_program_by_title(struct trace *trace __maybe_unused,
3590*4882a593Smuzhiyun const char *name __maybe_unused)
3591*4882a593Smuzhiyun {
3592*4882a593Smuzhiyun return NULL;
3593*4882a593Smuzhiyun }
3594*4882a593Smuzhiyun
3595*4882a593Smuzhiyun static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace __maybe_unused)
3596*4882a593Smuzhiyun {
3597*4882a593Smuzhiyun return 0;
3598*4882a593Smuzhiyun }
3599*4882a593Smuzhiyun
3600*4882a593Smuzhiyun static void trace__delete_augmented_syscalls(struct trace *trace __maybe_unused)
3601*4882a593Smuzhiyun {
3602*4882a593Smuzhiyun }
3603*4882a593Smuzhiyun #endif // HAVE_LIBBPF_SUPPORT
3604*4882a593Smuzhiyun
3605*4882a593Smuzhiyun static bool trace__only_augmented_syscalls_evsels(struct trace *trace)
3606*4882a593Smuzhiyun {
3607*4882a593Smuzhiyun struct evsel *evsel;
3608*4882a593Smuzhiyun
3609*4882a593Smuzhiyun evlist__for_each_entry(trace->evlist, evsel) {
3610*4882a593Smuzhiyun if (evsel == trace->syscalls.events.augmented ||
3611*4882a593Smuzhiyun evsel->bpf_obj == trace->bpf_obj)
3612*4882a593Smuzhiyun continue;
3613*4882a593Smuzhiyun
3614*4882a593Smuzhiyun return false;
3615*4882a593Smuzhiyun }
3616*4882a593Smuzhiyun
3617*4882a593Smuzhiyun return true;
3618*4882a593Smuzhiyun }
3619*4882a593Smuzhiyun
3620*4882a593Smuzhiyun static int trace__set_ev_qualifier_filter(struct trace *trace)
3621*4882a593Smuzhiyun {
3622*4882a593Smuzhiyun if (trace->syscalls.map)
3623*4882a593Smuzhiyun return trace__set_ev_qualifier_bpf_filter(trace);
3624*4882a593Smuzhiyun if (trace->syscalls.events.sys_enter)
3625*4882a593Smuzhiyun return trace__set_ev_qualifier_tp_filter(trace);
3626*4882a593Smuzhiyun return 0;
3627*4882a593Smuzhiyun }
3628*4882a593Smuzhiyun
3629*4882a593Smuzhiyun static int bpf_map__set_filter_pids(struct bpf_map *map __maybe_unused,
3630*4882a593Smuzhiyun size_t npids __maybe_unused, pid_t *pids __maybe_unused)
3631*4882a593Smuzhiyun {
3632*4882a593Smuzhiyun int err = 0;
3633*4882a593Smuzhiyun #ifdef HAVE_LIBBPF_SUPPORT
3634*4882a593Smuzhiyun bool value = true;
3635*4882a593Smuzhiyun int map_fd = bpf_map__fd(map);
3636*4882a593Smuzhiyun size_t i;
3637*4882a593Smuzhiyun
3638*4882a593Smuzhiyun for (i = 0; i < npids; ++i) {
3639*4882a593Smuzhiyun err = bpf_map_update_elem(map_fd, &pids[i], &value, BPF_ANY);
3640*4882a593Smuzhiyun if (err)
3641*4882a593Smuzhiyun break;
3642*4882a593Smuzhiyun }
3643*4882a593Smuzhiyun #endif
3644*4882a593Smuzhiyun return err;
3645*4882a593Smuzhiyun }
3646*4882a593Smuzhiyun
3647*4882a593Smuzhiyun static int trace__set_filter_loop_pids(struct trace *trace)
3648*4882a593Smuzhiyun {
3649*4882a593Smuzhiyun unsigned int nr = 1, err;
3650*4882a593Smuzhiyun pid_t pids[32] = {
3651*4882a593Smuzhiyun getpid(),
3652*4882a593Smuzhiyun };
3653*4882a593Smuzhiyun struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
3654*4882a593Smuzhiyun
3655*4882a593Smuzhiyun while (thread && nr < ARRAY_SIZE(pids)) {
3656*4882a593Smuzhiyun struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
3657*4882a593Smuzhiyun
3658*4882a593Smuzhiyun if (parent == NULL)
3659*4882a593Smuzhiyun break;
3660*4882a593Smuzhiyun
3661*4882a593Smuzhiyun if (!strcmp(thread__comm_str(parent), "sshd") ||
3662*4882a593Smuzhiyun strstarts(thread__comm_str(parent), "gnome-terminal")) {
3663*4882a593Smuzhiyun pids[nr++] = parent->tid;
3664*4882a593Smuzhiyun break;
3665*4882a593Smuzhiyun }
3666*4882a593Smuzhiyun thread = parent;
3667*4882a593Smuzhiyun }
3668*4882a593Smuzhiyun
3669*4882a593Smuzhiyun err = perf_evlist__append_tp_filter_pids(trace->evlist, nr, pids);
3670*4882a593Smuzhiyun if (!err && trace->filter_pids.map)
3671*4882a593Smuzhiyun err = bpf_map__set_filter_pids(trace->filter_pids.map, nr, pids);
3672*4882a593Smuzhiyun
3673*4882a593Smuzhiyun return err;
3674*4882a593Smuzhiyun }
3675*4882a593Smuzhiyun
3676*4882a593Smuzhiyun static int trace__set_filter_pids(struct trace *trace)
3677*4882a593Smuzhiyun {
3678*4882a593Smuzhiyun int err = 0;
3679*4882a593Smuzhiyun /*
3680*4882a593Smuzhiyun * Better not use !target__has_task() here because we need to cover the
3681*4882a593Smuzhiyun * case where no threads were specified in the command line, but a
3682*4882a593Smuzhiyun * workload was, and in that case we will fill in the thread_map when
3683*4882a593Smuzhiyun * we fork the workload in perf_evlist__prepare_workload.
3684*4882a593Smuzhiyun */
3685*4882a593Smuzhiyun if (trace->filter_pids.nr > 0) {
3686*4882a593Smuzhiyun err = perf_evlist__append_tp_filter_pids(trace->evlist, trace->filter_pids.nr,
3687*4882a593Smuzhiyun trace->filter_pids.entries);
3688*4882a593Smuzhiyun if (!err && trace->filter_pids.map) {
3689*4882a593Smuzhiyun err = bpf_map__set_filter_pids(trace->filter_pids.map, trace->filter_pids.nr,
3690*4882a593Smuzhiyun trace->filter_pids.entries);
3691*4882a593Smuzhiyun }
3692*4882a593Smuzhiyun } else if (perf_thread_map__pid(trace->evlist->core.threads, 0) == -1) {
3693*4882a593Smuzhiyun err = trace__set_filter_loop_pids(trace);
3694*4882a593Smuzhiyun }
3695*4882a593Smuzhiyun
3696*4882a593Smuzhiyun return err;
3697*4882a593Smuzhiyun }
3698*4882a593Smuzhiyun
3699*4882a593Smuzhiyun static int __trace__deliver_event(struct trace *trace, union perf_event *event)
3700*4882a593Smuzhiyun {
3701*4882a593Smuzhiyun struct evlist *evlist = trace->evlist;
3702*4882a593Smuzhiyun struct perf_sample sample;
3703*4882a593Smuzhiyun int err;
3704*4882a593Smuzhiyun
3705*4882a593Smuzhiyun err = perf_evlist__parse_sample(evlist, event, &sample);
3706*4882a593Smuzhiyun if (err)
3707*4882a593Smuzhiyun fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
3708*4882a593Smuzhiyun else
3709*4882a593Smuzhiyun trace__handle_event(trace, event, &sample);
3710*4882a593Smuzhiyun
3711*4882a593Smuzhiyun return 0;
3712*4882a593Smuzhiyun }
3713*4882a593Smuzhiyun
3714*4882a593Smuzhiyun static int __trace__flush_events(struct trace *trace)
3715*4882a593Smuzhiyun {
3716*4882a593Smuzhiyun u64 first = ordered_events__first_time(&trace->oe.data);
3717*4882a593Smuzhiyun u64 flush = trace->oe.last - NSEC_PER_SEC;
3718*4882a593Smuzhiyun
3719*4882a593Smuzhiyun /* Is there some thing to flush.. */
3720*4882a593Smuzhiyun if (first && first < flush)
3721*4882a593Smuzhiyun return ordered_events__flush_time(&trace->oe.data, flush);
3722*4882a593Smuzhiyun
3723*4882a593Smuzhiyun return 0;
3724*4882a593Smuzhiyun }
3725*4882a593Smuzhiyun
3726*4882a593Smuzhiyun static int trace__flush_events(struct trace *trace)
3727*4882a593Smuzhiyun {
3728*4882a593Smuzhiyun return !trace->sort_events ? 0 : __trace__flush_events(trace);
3729*4882a593Smuzhiyun }
3730*4882a593Smuzhiyun
3731*4882a593Smuzhiyun static int trace__deliver_event(struct trace *trace, union perf_event *event)
3732*4882a593Smuzhiyun {
3733*4882a593Smuzhiyun int err;
3734*4882a593Smuzhiyun
3735*4882a593Smuzhiyun if (!trace->sort_events)
3736*4882a593Smuzhiyun return __trace__deliver_event(trace, event);
3737*4882a593Smuzhiyun
3738*4882a593Smuzhiyun err = perf_evlist__parse_sample_timestamp(trace->evlist, event, &trace->oe.last);
3739*4882a593Smuzhiyun if (err && err != -1)
3740*4882a593Smuzhiyun return err;
3741*4882a593Smuzhiyun
3742*4882a593Smuzhiyun err = ordered_events__queue(&trace->oe.data, event, trace->oe.last, 0);
3743*4882a593Smuzhiyun if (err)
3744*4882a593Smuzhiyun return err;
3745*4882a593Smuzhiyun
3746*4882a593Smuzhiyun return trace__flush_events(trace);
3747*4882a593Smuzhiyun }
3748*4882a593Smuzhiyun
3749*4882a593Smuzhiyun static int ordered_events__deliver_event(struct ordered_events *oe,
3750*4882a593Smuzhiyun struct ordered_event *event)
3751*4882a593Smuzhiyun {
3752*4882a593Smuzhiyun struct trace *trace = container_of(oe, struct trace, oe.data);
3753*4882a593Smuzhiyun
3754*4882a593Smuzhiyun return __trace__deliver_event(trace, event->event);
3755*4882a593Smuzhiyun }
3756*4882a593Smuzhiyun
3757*4882a593Smuzhiyun static struct syscall_arg_fmt *evsel__find_syscall_arg_fmt_by_name(struct evsel *evsel, char *arg)
3758*4882a593Smuzhiyun {
3759*4882a593Smuzhiyun struct tep_format_field *field;
3760*4882a593Smuzhiyun struct syscall_arg_fmt *fmt = __evsel__syscall_arg_fmt(evsel);
3761*4882a593Smuzhiyun
3762*4882a593Smuzhiyun if (evsel->tp_format == NULL || fmt == NULL)
3763*4882a593Smuzhiyun return NULL;
3764*4882a593Smuzhiyun
3765*4882a593Smuzhiyun for (field = evsel->tp_format->format.fields; field; field = field->next, ++fmt)
3766*4882a593Smuzhiyun if (strcmp(field->name, arg) == 0)
3767*4882a593Smuzhiyun return fmt;
3768*4882a593Smuzhiyun
3769*4882a593Smuzhiyun return NULL;
3770*4882a593Smuzhiyun }
3771*4882a593Smuzhiyun
3772*4882a593Smuzhiyun static int trace__expand_filter(struct trace *trace __maybe_unused, struct evsel *evsel)
3773*4882a593Smuzhiyun {
3774*4882a593Smuzhiyun char *tok, *left = evsel->filter, *new_filter = evsel->filter;
3775*4882a593Smuzhiyun
3776*4882a593Smuzhiyun while ((tok = strpbrk(left, "=<>!")) != NULL) {
3777*4882a593Smuzhiyun char *right = tok + 1, *right_end;
3778*4882a593Smuzhiyun
3779*4882a593Smuzhiyun if (*right == '=')
3780*4882a593Smuzhiyun ++right;
3781*4882a593Smuzhiyun
3782*4882a593Smuzhiyun while (isspace(*right))
3783*4882a593Smuzhiyun ++right;
3784*4882a593Smuzhiyun
3785*4882a593Smuzhiyun if (*right == '\0')
3786*4882a593Smuzhiyun break;
3787*4882a593Smuzhiyun
3788*4882a593Smuzhiyun while (!isalpha(*left))
3789*4882a593Smuzhiyun if (++left == tok) {
3790*4882a593Smuzhiyun /*
3791*4882a593Smuzhiyun * Bail out, can't find the name of the argument that is being
3792*4882a593Smuzhiyun * used in the filter, let it try to set this filter, will fail later.
3793*4882a593Smuzhiyun */
3794*4882a593Smuzhiyun return 0;
3795*4882a593Smuzhiyun }
3796*4882a593Smuzhiyun
3797*4882a593Smuzhiyun right_end = right + 1;
3798*4882a593Smuzhiyun while (isalnum(*right_end) || *right_end == '_' || *right_end == '|')
3799*4882a593Smuzhiyun ++right_end;
3800*4882a593Smuzhiyun
3801*4882a593Smuzhiyun if (isalpha(*right)) {
3802*4882a593Smuzhiyun struct syscall_arg_fmt *fmt;
3803*4882a593Smuzhiyun int left_size = tok - left,
3804*4882a593Smuzhiyun right_size = right_end - right;
3805*4882a593Smuzhiyun char arg[128];
3806*4882a593Smuzhiyun
3807*4882a593Smuzhiyun while (isspace(left[left_size - 1]))
3808*4882a593Smuzhiyun --left_size;
3809*4882a593Smuzhiyun
3810*4882a593Smuzhiyun scnprintf(arg, sizeof(arg), "%.*s", left_size, left);
3811*4882a593Smuzhiyun
3812*4882a593Smuzhiyun fmt = evsel__find_syscall_arg_fmt_by_name(evsel, arg);
3813*4882a593Smuzhiyun if (fmt == NULL) {
3814*4882a593Smuzhiyun pr_err("\"%s\" not found in \"%s\", can't set filter \"%s\"\n",
3815*4882a593Smuzhiyun arg, evsel->name, evsel->filter);
3816*4882a593Smuzhiyun return -1;
3817*4882a593Smuzhiyun }
3818*4882a593Smuzhiyun
3819*4882a593Smuzhiyun pr_debug2("trying to expand \"%s\" \"%.*s\" \"%.*s\" -> ",
3820*4882a593Smuzhiyun arg, (int)(right - tok), tok, right_size, right);
3821*4882a593Smuzhiyun
3822*4882a593Smuzhiyun if (fmt->strtoul) {
3823*4882a593Smuzhiyun u64 val;
3824*4882a593Smuzhiyun struct syscall_arg syscall_arg = {
3825*4882a593Smuzhiyun .parm = fmt->parm,
3826*4882a593Smuzhiyun };
3827*4882a593Smuzhiyun
3828*4882a593Smuzhiyun if (fmt->strtoul(right, right_size, &syscall_arg, &val)) {
3829*4882a593Smuzhiyun char *n, expansion[19];
3830*4882a593Smuzhiyun int expansion_lenght = scnprintf(expansion, sizeof(expansion), "%#" PRIx64, val);
3831*4882a593Smuzhiyun int expansion_offset = right - new_filter;
3832*4882a593Smuzhiyun
3833*4882a593Smuzhiyun pr_debug("%s", expansion);
3834*4882a593Smuzhiyun
3835*4882a593Smuzhiyun if (asprintf(&n, "%.*s%s%s", expansion_offset, new_filter, expansion, right_end) < 0) {
3836*4882a593Smuzhiyun pr_debug(" out of memory!\n");
3837*4882a593Smuzhiyun free(new_filter);
3838*4882a593Smuzhiyun return -1;
3839*4882a593Smuzhiyun }
3840*4882a593Smuzhiyun if (new_filter != evsel->filter)
3841*4882a593Smuzhiyun free(new_filter);
3842*4882a593Smuzhiyun left = n + expansion_offset + expansion_lenght;
3843*4882a593Smuzhiyun new_filter = n;
3844*4882a593Smuzhiyun } else {
3845*4882a593Smuzhiyun pr_err("\"%.*s\" not found for \"%s\" in \"%s\", can't set filter \"%s\"\n",
3846*4882a593Smuzhiyun right_size, right, arg, evsel->name, evsel->filter);
3847*4882a593Smuzhiyun return -1;
3848*4882a593Smuzhiyun }
3849*4882a593Smuzhiyun } else {
3850*4882a593Smuzhiyun pr_err("No resolver (strtoul) for \"%s\" in \"%s\", can't set filter \"%s\"\n",
3851*4882a593Smuzhiyun arg, evsel->name, evsel->filter);
3852*4882a593Smuzhiyun return -1;
3853*4882a593Smuzhiyun }
3854*4882a593Smuzhiyun
3855*4882a593Smuzhiyun pr_debug("\n");
3856*4882a593Smuzhiyun } else {
3857*4882a593Smuzhiyun left = right_end;
3858*4882a593Smuzhiyun }
3859*4882a593Smuzhiyun }
3860*4882a593Smuzhiyun
3861*4882a593Smuzhiyun if (new_filter != evsel->filter) {
3862*4882a593Smuzhiyun pr_debug("New filter for %s: %s\n", evsel->name, new_filter);
3863*4882a593Smuzhiyun evsel__set_filter(evsel, new_filter);
3864*4882a593Smuzhiyun free(new_filter);
3865*4882a593Smuzhiyun }
3866*4882a593Smuzhiyun
3867*4882a593Smuzhiyun return 0;
3868*4882a593Smuzhiyun }
3869*4882a593Smuzhiyun
3870*4882a593Smuzhiyun static int trace__expand_filters(struct trace *trace, struct evsel **err_evsel)
3871*4882a593Smuzhiyun {
3872*4882a593Smuzhiyun struct evlist *evlist = trace->evlist;
3873*4882a593Smuzhiyun struct evsel *evsel;
3874*4882a593Smuzhiyun
3875*4882a593Smuzhiyun evlist__for_each_entry(evlist, evsel) {
3876*4882a593Smuzhiyun if (evsel->filter == NULL)
3877*4882a593Smuzhiyun continue;
3878*4882a593Smuzhiyun
3879*4882a593Smuzhiyun if (trace__expand_filter(trace, evsel)) {
3880*4882a593Smuzhiyun *err_evsel = evsel;
3881*4882a593Smuzhiyun return -1;
3882*4882a593Smuzhiyun }
3883*4882a593Smuzhiyun }
3884*4882a593Smuzhiyun
3885*4882a593Smuzhiyun return 0;
3886*4882a593Smuzhiyun }
3887*4882a593Smuzhiyun
3888*4882a593Smuzhiyun static int trace__run(struct trace *trace, int argc, const char **argv)
3889*4882a593Smuzhiyun {
3890*4882a593Smuzhiyun struct evlist *evlist = trace->evlist;
3891*4882a593Smuzhiyun struct evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
3892*4882a593Smuzhiyun int err = -1, i;
3893*4882a593Smuzhiyun unsigned long before;
3894*4882a593Smuzhiyun const bool forks = argc > 0;
3895*4882a593Smuzhiyun bool draining = false;
3896*4882a593Smuzhiyun
3897*4882a593Smuzhiyun trace->live = true;
3898*4882a593Smuzhiyun
3899*4882a593Smuzhiyun if (!trace->raw_augmented_syscalls) {
3900*4882a593Smuzhiyun if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
3901*4882a593Smuzhiyun goto out_error_raw_syscalls;
3902*4882a593Smuzhiyun
3903*4882a593Smuzhiyun if (trace->trace_syscalls)
3904*4882a593Smuzhiyun trace->vfs_getname = evlist__add_vfs_getname(evlist);
3905*4882a593Smuzhiyun }
3906*4882a593Smuzhiyun
3907*4882a593Smuzhiyun if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
3908*4882a593Smuzhiyun pgfault_maj = evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
3909*4882a593Smuzhiyun if (pgfault_maj == NULL)
3910*4882a593Smuzhiyun goto out_error_mem;
3911*4882a593Smuzhiyun evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
3912*4882a593Smuzhiyun evlist__add(evlist, pgfault_maj);
3913*4882a593Smuzhiyun }
3914*4882a593Smuzhiyun
3915*4882a593Smuzhiyun if ((trace->trace_pgfaults & TRACE_PFMIN)) {
3916*4882a593Smuzhiyun pgfault_min = evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
3917*4882a593Smuzhiyun if (pgfault_min == NULL)
3918*4882a593Smuzhiyun goto out_error_mem;
3919*4882a593Smuzhiyun evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
3920*4882a593Smuzhiyun evlist__add(evlist, pgfault_min);
3921*4882a593Smuzhiyun }
3922*4882a593Smuzhiyun
3923*4882a593Smuzhiyun if (trace->sched &&
3924*4882a593Smuzhiyun evlist__add_newtp(evlist, "sched", "sched_stat_runtime", trace__sched_stat_runtime))
3925*4882a593Smuzhiyun goto out_error_sched_stat_runtime;
3926*4882a593Smuzhiyun /*
3927*4882a593Smuzhiyun * If a global cgroup was set, apply it to all the events without an
3928*4882a593Smuzhiyun * explicit cgroup. I.e.:
3929*4882a593Smuzhiyun *
3930*4882a593Smuzhiyun * trace -G A -e sched:*switch
3931*4882a593Smuzhiyun *
3932*4882a593Smuzhiyun * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
3933*4882a593Smuzhiyun * _and_ sched:sched_switch to the 'A' cgroup, while:
3934*4882a593Smuzhiyun *
3935*4882a593Smuzhiyun * trace -e sched:*switch -G A
3936*4882a593Smuzhiyun *
3937*4882a593Smuzhiyun * will only set the sched:sched_switch event to the 'A' cgroup, all the
3938*4882a593Smuzhiyun * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
3939*4882a593Smuzhiyun * a cgroup (on the root cgroup, sys wide, etc).
3940*4882a593Smuzhiyun *
3941*4882a593Smuzhiyun * Multiple cgroups:
3942*4882a593Smuzhiyun *
3943*4882a593Smuzhiyun * trace -G A -e sched:*switch -G B
3944*4882a593Smuzhiyun *
3945*4882a593Smuzhiyun * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
3946*4882a593Smuzhiyun * to the 'B' cgroup.
3947*4882a593Smuzhiyun *
3948*4882a593Smuzhiyun * evlist__set_default_cgroup() grabs a reference of the passed cgroup
3949*4882a593Smuzhiyun * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
3950*4882a593Smuzhiyun */
3951*4882a593Smuzhiyun if (trace->cgroup)
3952*4882a593Smuzhiyun evlist__set_default_cgroup(trace->evlist, trace->cgroup);
3953*4882a593Smuzhiyun
3954*4882a593Smuzhiyun err = perf_evlist__create_maps(evlist, &trace->opts.target);
3955*4882a593Smuzhiyun if (err < 0) {
3956*4882a593Smuzhiyun fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
3957*4882a593Smuzhiyun goto out_delete_evlist;
3958*4882a593Smuzhiyun }
3959*4882a593Smuzhiyun
3960*4882a593Smuzhiyun err = trace__symbols_init(trace, evlist);
3961*4882a593Smuzhiyun if (err < 0) {
3962*4882a593Smuzhiyun fprintf(trace->output, "Problems initializing symbol libraries!\n");
3963*4882a593Smuzhiyun goto out_delete_evlist;
3964*4882a593Smuzhiyun }
3965*4882a593Smuzhiyun
3966*4882a593Smuzhiyun perf_evlist__config(evlist, &trace->opts, &callchain_param);
3967*4882a593Smuzhiyun
3968*4882a593Smuzhiyun signal(SIGCHLD, sig_handler);
3969*4882a593Smuzhiyun signal(SIGINT, sig_handler);
3970*4882a593Smuzhiyun
3971*4882a593Smuzhiyun if (forks) {
3972*4882a593Smuzhiyun err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
3973*4882a593Smuzhiyun argv, false, NULL);
3974*4882a593Smuzhiyun if (err < 0) {
3975*4882a593Smuzhiyun fprintf(trace->output, "Couldn't run the workload!\n");
3976*4882a593Smuzhiyun goto out_delete_evlist;
3977*4882a593Smuzhiyun }
3978*4882a593Smuzhiyun }
3979*4882a593Smuzhiyun
3980*4882a593Smuzhiyun err = evlist__open(evlist);
3981*4882a593Smuzhiyun if (err < 0)
3982*4882a593Smuzhiyun goto out_error_open;
3983*4882a593Smuzhiyun
3984*4882a593Smuzhiyun err = bpf__apply_obj_config();
3985*4882a593Smuzhiyun if (err) {
3986*4882a593Smuzhiyun char errbuf[BUFSIZ];
3987*4882a593Smuzhiyun
3988*4882a593Smuzhiyun bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
3989*4882a593Smuzhiyun pr_err("ERROR: Apply config to BPF failed: %s\n",
3990*4882a593Smuzhiyun errbuf);
3991*4882a593Smuzhiyun goto out_error_open;
3992*4882a593Smuzhiyun }
3993*4882a593Smuzhiyun
3994*4882a593Smuzhiyun err = trace__set_filter_pids(trace);
3995*4882a593Smuzhiyun if (err < 0)
3996*4882a593Smuzhiyun goto out_error_mem;
3997*4882a593Smuzhiyun
3998*4882a593Smuzhiyun if (trace->syscalls.map)
3999*4882a593Smuzhiyun trace__init_syscalls_bpf_map(trace);
4000*4882a593Smuzhiyun
4001*4882a593Smuzhiyun if (trace->syscalls.prog_array.sys_enter)
4002*4882a593Smuzhiyun trace__init_syscalls_bpf_prog_array_maps(trace);
4003*4882a593Smuzhiyun
4004*4882a593Smuzhiyun if (trace->ev_qualifier_ids.nr > 0) {
4005*4882a593Smuzhiyun err = trace__set_ev_qualifier_filter(trace);
4006*4882a593Smuzhiyun if (err < 0)
4007*4882a593Smuzhiyun goto out_errno;
4008*4882a593Smuzhiyun
4009*4882a593Smuzhiyun if (trace->syscalls.events.sys_exit) {
4010*4882a593Smuzhiyun pr_debug("event qualifier tracepoint filter: %s\n",
4011*4882a593Smuzhiyun trace->syscalls.events.sys_exit->filter);
4012*4882a593Smuzhiyun }
4013*4882a593Smuzhiyun }
4014*4882a593Smuzhiyun
4015*4882a593Smuzhiyun /*
4016*4882a593Smuzhiyun * If the "close" syscall is not traced, then we will not have the
4017*4882a593Smuzhiyun * opportunity to, in syscall_arg__scnprintf_close_fd() invalidate the
4018*4882a593Smuzhiyun * fd->pathname table and were ending up showing the last value set by
4019*4882a593Smuzhiyun * syscalls opening a pathname and associating it with a descriptor or
4020*4882a593Smuzhiyun * reading it from /proc/pid/fd/ in cases where that doesn't make
4021*4882a593Smuzhiyun * sense.
4022*4882a593Smuzhiyun *
4023*4882a593Smuzhiyun * So just disable this beautifier (SCA_FD, SCA_FDAT) when 'close' is
4024*4882a593Smuzhiyun * not in use.
4025*4882a593Smuzhiyun */
4026*4882a593Smuzhiyun trace->fd_path_disabled = !trace__syscall_enabled(trace, syscalltbl__id(trace->sctbl, "close"));
4027*4882a593Smuzhiyun
4028*4882a593Smuzhiyun err = trace__expand_filters(trace, &evsel);
4029*4882a593Smuzhiyun if (err)
4030*4882a593Smuzhiyun goto out_delete_evlist;
4031*4882a593Smuzhiyun err = perf_evlist__apply_filters(evlist, &evsel);
4032*4882a593Smuzhiyun if (err < 0)
4033*4882a593Smuzhiyun goto out_error_apply_filters;
4034*4882a593Smuzhiyun
4035*4882a593Smuzhiyun if (trace->dump.map)
4036*4882a593Smuzhiyun bpf_map__fprintf(trace->dump.map, trace->output);
4037*4882a593Smuzhiyun
4038*4882a593Smuzhiyun err = evlist__mmap(evlist, trace->opts.mmap_pages);
4039*4882a593Smuzhiyun if (err < 0)
4040*4882a593Smuzhiyun goto out_error_mmap;
4041*4882a593Smuzhiyun
4042*4882a593Smuzhiyun if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
4043*4882a593Smuzhiyun evlist__enable(evlist);
4044*4882a593Smuzhiyun
4045*4882a593Smuzhiyun if (forks)
4046*4882a593Smuzhiyun perf_evlist__start_workload(evlist);
4047*4882a593Smuzhiyun
4048*4882a593Smuzhiyun if (trace->opts.initial_delay) {
4049*4882a593Smuzhiyun usleep(trace->opts.initial_delay * 1000);
4050*4882a593Smuzhiyun evlist__enable(evlist);
4051*4882a593Smuzhiyun }
4052*4882a593Smuzhiyun
4053*4882a593Smuzhiyun trace->multiple_threads = perf_thread_map__pid(evlist->core.threads, 0) == -1 ||
4054*4882a593Smuzhiyun evlist->core.threads->nr > 1 ||
4055*4882a593Smuzhiyun evlist__first(evlist)->core.attr.inherit;
4056*4882a593Smuzhiyun
4057*4882a593Smuzhiyun /*
4058*4882a593Smuzhiyun * Now that we already used evsel->core.attr to ask the kernel to setup the
4059*4882a593Smuzhiyun * events, lets reuse evsel->core.attr.sample_max_stack as the limit in
4060*4882a593Smuzhiyun * trace__resolve_callchain(), allowing per-event max-stack settings
4061*4882a593Smuzhiyun * to override an explicitly set --max-stack global setting.
4062*4882a593Smuzhiyun */
4063*4882a593Smuzhiyun evlist__for_each_entry(evlist, evsel) {
4064*4882a593Smuzhiyun if (evsel__has_callchain(evsel) &&
4065*4882a593Smuzhiyun evsel->core.attr.sample_max_stack == 0)
4066*4882a593Smuzhiyun evsel->core.attr.sample_max_stack = trace->max_stack;
4067*4882a593Smuzhiyun }
4068*4882a593Smuzhiyun again:
4069*4882a593Smuzhiyun before = trace->nr_events;
4070*4882a593Smuzhiyun
4071*4882a593Smuzhiyun for (i = 0; i < evlist->core.nr_mmaps; i++) {
4072*4882a593Smuzhiyun union perf_event *event;
4073*4882a593Smuzhiyun struct mmap *md;
4074*4882a593Smuzhiyun
4075*4882a593Smuzhiyun md = &evlist->mmap[i];
4076*4882a593Smuzhiyun if (perf_mmap__read_init(&md->core) < 0)
4077*4882a593Smuzhiyun continue;
4078*4882a593Smuzhiyun
4079*4882a593Smuzhiyun while ((event = perf_mmap__read_event(&md->core)) != NULL) {
4080*4882a593Smuzhiyun ++trace->nr_events;
4081*4882a593Smuzhiyun
4082*4882a593Smuzhiyun err = trace__deliver_event(trace, event);
4083*4882a593Smuzhiyun if (err)
4084*4882a593Smuzhiyun goto out_disable;
4085*4882a593Smuzhiyun
4086*4882a593Smuzhiyun perf_mmap__consume(&md->core);
4087*4882a593Smuzhiyun
4088*4882a593Smuzhiyun if (interrupted)
4089*4882a593Smuzhiyun goto out_disable;
4090*4882a593Smuzhiyun
4091*4882a593Smuzhiyun if (done && !draining) {
4092*4882a593Smuzhiyun evlist__disable(evlist);
4093*4882a593Smuzhiyun draining = true;
4094*4882a593Smuzhiyun }
4095*4882a593Smuzhiyun }
4096*4882a593Smuzhiyun perf_mmap__read_done(&md->core);
4097*4882a593Smuzhiyun }
4098*4882a593Smuzhiyun
4099*4882a593Smuzhiyun if (trace->nr_events == before) {
4100*4882a593Smuzhiyun int timeout = done ? 100 : -1;
4101*4882a593Smuzhiyun
4102*4882a593Smuzhiyun if (!draining && evlist__poll(evlist, timeout) > 0) {
4103*4882a593Smuzhiyun if (evlist__filter_pollfd(evlist, POLLERR | POLLHUP | POLLNVAL) == 0)
4104*4882a593Smuzhiyun draining = true;
4105*4882a593Smuzhiyun
4106*4882a593Smuzhiyun goto again;
4107*4882a593Smuzhiyun } else {
4108*4882a593Smuzhiyun if (trace__flush_events(trace))
4109*4882a593Smuzhiyun goto out_disable;
4110*4882a593Smuzhiyun }
4111*4882a593Smuzhiyun } else {
4112*4882a593Smuzhiyun goto again;
4113*4882a593Smuzhiyun }
4114*4882a593Smuzhiyun
4115*4882a593Smuzhiyun out_disable:
4116*4882a593Smuzhiyun thread__zput(trace->current);
4117*4882a593Smuzhiyun
4118*4882a593Smuzhiyun evlist__disable(evlist);
4119*4882a593Smuzhiyun
4120*4882a593Smuzhiyun if (trace->sort_events)
4121*4882a593Smuzhiyun ordered_events__flush(&trace->oe.data, OE_FLUSH__FINAL);
4122*4882a593Smuzhiyun
4123*4882a593Smuzhiyun if (!err) {
4124*4882a593Smuzhiyun if (trace->summary)
4125*4882a593Smuzhiyun trace__fprintf_thread_summary(trace, trace->output);
4126*4882a593Smuzhiyun
4127*4882a593Smuzhiyun if (trace->show_tool_stats) {
4128*4882a593Smuzhiyun fprintf(trace->output, "Stats:\n "
4129*4882a593Smuzhiyun " vfs_getname : %" PRIu64 "\n"
4130*4882a593Smuzhiyun " proc_getname: %" PRIu64 "\n",
4131*4882a593Smuzhiyun trace->stats.vfs_getname,
4132*4882a593Smuzhiyun trace->stats.proc_getname);
4133*4882a593Smuzhiyun }
4134*4882a593Smuzhiyun }
4135*4882a593Smuzhiyun
4136*4882a593Smuzhiyun out_delete_evlist:
4137*4882a593Smuzhiyun trace__symbols__exit(trace);
4138*4882a593Smuzhiyun
4139*4882a593Smuzhiyun evlist__delete(evlist);
4140*4882a593Smuzhiyun cgroup__put(trace->cgroup);
4141*4882a593Smuzhiyun trace->evlist = NULL;
4142*4882a593Smuzhiyun trace->live = false;
4143*4882a593Smuzhiyun return err;
4144*4882a593Smuzhiyun {
4145*4882a593Smuzhiyun char errbuf[BUFSIZ];
4146*4882a593Smuzhiyun
4147*4882a593Smuzhiyun out_error_sched_stat_runtime:
4148*4882a593Smuzhiyun tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
4149*4882a593Smuzhiyun goto out_error;
4150*4882a593Smuzhiyun
4151*4882a593Smuzhiyun out_error_raw_syscalls:
4152*4882a593Smuzhiyun tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
4153*4882a593Smuzhiyun goto out_error;
4154*4882a593Smuzhiyun
4155*4882a593Smuzhiyun out_error_mmap:
4156*4882a593Smuzhiyun evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
4157*4882a593Smuzhiyun goto out_error;
4158*4882a593Smuzhiyun
4159*4882a593Smuzhiyun out_error_open:
4160*4882a593Smuzhiyun evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
4161*4882a593Smuzhiyun
4162*4882a593Smuzhiyun out_error:
4163*4882a593Smuzhiyun fprintf(trace->output, "%s\n", errbuf);
4164*4882a593Smuzhiyun goto out_delete_evlist;
4165*4882a593Smuzhiyun
4166*4882a593Smuzhiyun out_error_apply_filters:
4167*4882a593Smuzhiyun fprintf(trace->output,
4168*4882a593Smuzhiyun "Failed to set filter \"%s\" on event %s with %d (%s)\n",
4169*4882a593Smuzhiyun evsel->filter, evsel__name(evsel), errno,
4170*4882a593Smuzhiyun str_error_r(errno, errbuf, sizeof(errbuf)));
4171*4882a593Smuzhiyun goto out_delete_evlist;
4172*4882a593Smuzhiyun }
4173*4882a593Smuzhiyun out_error_mem:
4174*4882a593Smuzhiyun fprintf(trace->output, "Not enough memory to run!\n");
4175*4882a593Smuzhiyun goto out_delete_evlist;
4176*4882a593Smuzhiyun
4177*4882a593Smuzhiyun out_errno:
4178*4882a593Smuzhiyun fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
4179*4882a593Smuzhiyun goto out_delete_evlist;
4180*4882a593Smuzhiyun }
4181*4882a593Smuzhiyun
4182*4882a593Smuzhiyun static int trace__replay(struct trace *trace)
4183*4882a593Smuzhiyun {
4184*4882a593Smuzhiyun const struct evsel_str_handler handlers[] = {
4185*4882a593Smuzhiyun { "probe:vfs_getname", trace__vfs_getname, },
4186*4882a593Smuzhiyun };
4187*4882a593Smuzhiyun struct perf_data data = {
4188*4882a593Smuzhiyun .path = input_name,
4189*4882a593Smuzhiyun .mode = PERF_DATA_MODE_READ,
4190*4882a593Smuzhiyun .force = trace->force,
4191*4882a593Smuzhiyun };
4192*4882a593Smuzhiyun struct perf_session *session;
4193*4882a593Smuzhiyun struct evsel *evsel;
4194*4882a593Smuzhiyun int err = -1;
4195*4882a593Smuzhiyun
4196*4882a593Smuzhiyun trace->tool.sample = trace__process_sample;
4197*4882a593Smuzhiyun trace->tool.mmap = perf_event__process_mmap;
4198*4882a593Smuzhiyun trace->tool.mmap2 = perf_event__process_mmap2;
4199*4882a593Smuzhiyun trace->tool.comm = perf_event__process_comm;
4200*4882a593Smuzhiyun trace->tool.exit = perf_event__process_exit;
4201*4882a593Smuzhiyun trace->tool.fork = perf_event__process_fork;
4202*4882a593Smuzhiyun trace->tool.attr = perf_event__process_attr;
4203*4882a593Smuzhiyun trace->tool.tracing_data = perf_event__process_tracing_data;
4204*4882a593Smuzhiyun trace->tool.build_id = perf_event__process_build_id;
4205*4882a593Smuzhiyun trace->tool.namespaces = perf_event__process_namespaces;
4206*4882a593Smuzhiyun
4207*4882a593Smuzhiyun trace->tool.ordered_events = true;
4208*4882a593Smuzhiyun trace->tool.ordering_requires_timestamps = true;
4209*4882a593Smuzhiyun
4210*4882a593Smuzhiyun /* add tid to output */
4211*4882a593Smuzhiyun trace->multiple_threads = true;
4212*4882a593Smuzhiyun
4213*4882a593Smuzhiyun session = perf_session__new(&data, false, &trace->tool);
4214*4882a593Smuzhiyun if (IS_ERR(session))
4215*4882a593Smuzhiyun return PTR_ERR(session);
4216*4882a593Smuzhiyun
4217*4882a593Smuzhiyun if (trace->opts.target.pid)
4218*4882a593Smuzhiyun symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
4219*4882a593Smuzhiyun
4220*4882a593Smuzhiyun if (trace->opts.target.tid)
4221*4882a593Smuzhiyun symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
4222*4882a593Smuzhiyun
4223*4882a593Smuzhiyun if (symbol__init(&session->header.env) < 0)
4224*4882a593Smuzhiyun goto out;
4225*4882a593Smuzhiyun
4226*4882a593Smuzhiyun trace->host = &session->machines.host;
4227*4882a593Smuzhiyun
4228*4882a593Smuzhiyun err = perf_session__set_tracepoints_handlers(session, handlers);
4229*4882a593Smuzhiyun if (err)
4230*4882a593Smuzhiyun goto out;
4231*4882a593Smuzhiyun
4232*4882a593Smuzhiyun evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
4233*4882a593Smuzhiyun "raw_syscalls:sys_enter");
4234*4882a593Smuzhiyun /* older kernels have syscalls tp versus raw_syscalls */
4235*4882a593Smuzhiyun if (evsel == NULL)
4236*4882a593Smuzhiyun evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
4237*4882a593Smuzhiyun "syscalls:sys_enter");
4238*4882a593Smuzhiyun
4239*4882a593Smuzhiyun if (evsel &&
4240*4882a593Smuzhiyun (evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
4241*4882a593Smuzhiyun perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
4242*4882a593Smuzhiyun pr_err("Error during initialize raw_syscalls:sys_enter event\n");
4243*4882a593Smuzhiyun goto out;
4244*4882a593Smuzhiyun }
4245*4882a593Smuzhiyun
4246*4882a593Smuzhiyun evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
4247*4882a593Smuzhiyun "raw_syscalls:sys_exit");
4248*4882a593Smuzhiyun if (evsel == NULL)
4249*4882a593Smuzhiyun evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
4250*4882a593Smuzhiyun "syscalls:sys_exit");
4251*4882a593Smuzhiyun if (evsel &&
4252*4882a593Smuzhiyun (evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
4253*4882a593Smuzhiyun perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
4254*4882a593Smuzhiyun pr_err("Error during initialize raw_syscalls:sys_exit event\n");
4255*4882a593Smuzhiyun goto out;
4256*4882a593Smuzhiyun }
4257*4882a593Smuzhiyun
4258*4882a593Smuzhiyun evlist__for_each_entry(session->evlist, evsel) {
4259*4882a593Smuzhiyun if (evsel->core.attr.type == PERF_TYPE_SOFTWARE &&
4260*4882a593Smuzhiyun (evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
4261*4882a593Smuzhiyun evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
4262*4882a593Smuzhiyun evsel->core.attr.config == PERF_COUNT_SW_PAGE_FAULTS))
4263*4882a593Smuzhiyun evsel->handler = trace__pgfault;
4264*4882a593Smuzhiyun }
4265*4882a593Smuzhiyun
4266*4882a593Smuzhiyun setup_pager();
4267*4882a593Smuzhiyun
4268*4882a593Smuzhiyun err = perf_session__process_events(session);
4269*4882a593Smuzhiyun if (err)
4270*4882a593Smuzhiyun pr_err("Failed to process events, error %d", err);
4271*4882a593Smuzhiyun
4272*4882a593Smuzhiyun else if (trace->summary)
4273*4882a593Smuzhiyun trace__fprintf_thread_summary(trace, trace->output);
4274*4882a593Smuzhiyun
4275*4882a593Smuzhiyun out:
4276*4882a593Smuzhiyun perf_session__delete(session);
4277*4882a593Smuzhiyun
4278*4882a593Smuzhiyun return err;
4279*4882a593Smuzhiyun }
4280*4882a593Smuzhiyun
4281*4882a593Smuzhiyun static size_t trace__fprintf_threads_header(FILE *fp)
4282*4882a593Smuzhiyun {
4283*4882a593Smuzhiyun size_t printed;
4284*4882a593Smuzhiyun
4285*4882a593Smuzhiyun printed = fprintf(fp, "\n Summary of events:\n\n");
4286*4882a593Smuzhiyun
4287*4882a593Smuzhiyun return printed;
4288*4882a593Smuzhiyun }
4289*4882a593Smuzhiyun
4290*4882a593Smuzhiyun DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
4291*4882a593Smuzhiyun struct syscall_stats *stats;
4292*4882a593Smuzhiyun double msecs;
4293*4882a593Smuzhiyun int syscall;
4294*4882a593Smuzhiyun )
4295*4882a593Smuzhiyun {
4296*4882a593Smuzhiyun struct int_node *source = rb_entry(nd, struct int_node, rb_node);
4297*4882a593Smuzhiyun struct syscall_stats *stats = source->priv;
4298*4882a593Smuzhiyun
4299*4882a593Smuzhiyun entry->syscall = source->i;
4300*4882a593Smuzhiyun entry->stats = stats;
4301*4882a593Smuzhiyun entry->msecs = stats ? (u64)stats->stats.n * (avg_stats(&stats->stats) / NSEC_PER_MSEC) : 0;
4302*4882a593Smuzhiyun }
4303*4882a593Smuzhiyun
4304*4882a593Smuzhiyun static size_t thread__dump_stats(struct thread_trace *ttrace,
4305*4882a593Smuzhiyun struct trace *trace, FILE *fp)
4306*4882a593Smuzhiyun {
4307*4882a593Smuzhiyun size_t printed = 0;
4308*4882a593Smuzhiyun struct syscall *sc;
4309*4882a593Smuzhiyun struct rb_node *nd;
4310*4882a593Smuzhiyun DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
4311*4882a593Smuzhiyun
4312*4882a593Smuzhiyun if (syscall_stats == NULL)
4313*4882a593Smuzhiyun return 0;
4314*4882a593Smuzhiyun
4315*4882a593Smuzhiyun printed += fprintf(fp, "\n");
4316*4882a593Smuzhiyun
4317*4882a593Smuzhiyun printed += fprintf(fp, " syscall calls errors total min avg max stddev\n");
4318*4882a593Smuzhiyun printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
4319*4882a593Smuzhiyun printed += fprintf(fp, " --------------- -------- ------ -------- --------- --------- --------- ------\n");
4320*4882a593Smuzhiyun
4321*4882a593Smuzhiyun resort_rb__for_each_entry(nd, syscall_stats) {
4322*4882a593Smuzhiyun struct syscall_stats *stats = syscall_stats_entry->stats;
4323*4882a593Smuzhiyun if (stats) {
4324*4882a593Smuzhiyun double min = (double)(stats->stats.min) / NSEC_PER_MSEC;
4325*4882a593Smuzhiyun double max = (double)(stats->stats.max) / NSEC_PER_MSEC;
4326*4882a593Smuzhiyun double avg = avg_stats(&stats->stats);
4327*4882a593Smuzhiyun double pct;
4328*4882a593Smuzhiyun u64 n = (u64)stats->stats.n;
4329*4882a593Smuzhiyun
4330*4882a593Smuzhiyun pct = avg ? 100.0 * stddev_stats(&stats->stats) / avg : 0.0;
4331*4882a593Smuzhiyun avg /= NSEC_PER_MSEC;
4332*4882a593Smuzhiyun
4333*4882a593Smuzhiyun sc = &trace->syscalls.table[syscall_stats_entry->syscall];
4334*4882a593Smuzhiyun printed += fprintf(fp, " %-15s", sc->name);
4335*4882a593Smuzhiyun printed += fprintf(fp, " %8" PRIu64 " %6" PRIu64 " %9.3f %9.3f %9.3f",
4336*4882a593Smuzhiyun n, stats->nr_failures, syscall_stats_entry->msecs, min, avg);
4337*4882a593Smuzhiyun printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
4338*4882a593Smuzhiyun
4339*4882a593Smuzhiyun if (trace->errno_summary && stats->nr_failures) {
4340*4882a593Smuzhiyun const char *arch_name = perf_env__arch(trace->host->env);
4341*4882a593Smuzhiyun int e;
4342*4882a593Smuzhiyun
4343*4882a593Smuzhiyun for (e = 0; e < stats->max_errno; ++e) {
4344*4882a593Smuzhiyun if (stats->errnos[e] != 0)
4345*4882a593Smuzhiyun fprintf(fp, "\t\t\t\t%s: %d\n", arch_syscalls__strerrno(arch_name, e + 1), stats->errnos[e]);
4346*4882a593Smuzhiyun }
4347*4882a593Smuzhiyun }
4348*4882a593Smuzhiyun }
4349*4882a593Smuzhiyun }
4350*4882a593Smuzhiyun
4351*4882a593Smuzhiyun resort_rb__delete(syscall_stats);
4352*4882a593Smuzhiyun printed += fprintf(fp, "\n\n");
4353*4882a593Smuzhiyun
4354*4882a593Smuzhiyun return printed;
4355*4882a593Smuzhiyun }
4356*4882a593Smuzhiyun
4357*4882a593Smuzhiyun static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
4358*4882a593Smuzhiyun {
4359*4882a593Smuzhiyun size_t printed = 0;
4360*4882a593Smuzhiyun struct thread_trace *ttrace = thread__priv(thread);
4361*4882a593Smuzhiyun double ratio;
4362*4882a593Smuzhiyun
4363*4882a593Smuzhiyun if (ttrace == NULL)
4364*4882a593Smuzhiyun return 0;
4365*4882a593Smuzhiyun
4366*4882a593Smuzhiyun ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
4367*4882a593Smuzhiyun
4368*4882a593Smuzhiyun printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
4369*4882a593Smuzhiyun printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
4370*4882a593Smuzhiyun printed += fprintf(fp, "%.1f%%", ratio);
4371*4882a593Smuzhiyun if (ttrace->pfmaj)
4372*4882a593Smuzhiyun printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
4373*4882a593Smuzhiyun if (ttrace->pfmin)
4374*4882a593Smuzhiyun printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
4375*4882a593Smuzhiyun if (trace->sched)
4376*4882a593Smuzhiyun printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
4377*4882a593Smuzhiyun else if (fputc('\n', fp) != EOF)
4378*4882a593Smuzhiyun ++printed;
4379*4882a593Smuzhiyun
4380*4882a593Smuzhiyun printed += thread__dump_stats(ttrace, trace, fp);
4381*4882a593Smuzhiyun
4382*4882a593Smuzhiyun return printed;
4383*4882a593Smuzhiyun }
4384*4882a593Smuzhiyun
4385*4882a593Smuzhiyun static unsigned long thread__nr_events(struct thread_trace *ttrace)
4386*4882a593Smuzhiyun {
4387*4882a593Smuzhiyun return ttrace ? ttrace->nr_events : 0;
4388*4882a593Smuzhiyun }
4389*4882a593Smuzhiyun
4390*4882a593Smuzhiyun DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
4391*4882a593Smuzhiyun struct thread *thread;
4392*4882a593Smuzhiyun )
4393*4882a593Smuzhiyun {
4394*4882a593Smuzhiyun entry->thread = rb_entry(nd, struct thread, rb_node);
4395*4882a593Smuzhiyun }
4396*4882a593Smuzhiyun
4397*4882a593Smuzhiyun static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
4398*4882a593Smuzhiyun {
4399*4882a593Smuzhiyun size_t printed = trace__fprintf_threads_header(fp);
4400*4882a593Smuzhiyun struct rb_node *nd;
4401*4882a593Smuzhiyun int i;
4402*4882a593Smuzhiyun
4403*4882a593Smuzhiyun for (i = 0; i < THREADS__TABLE_SIZE; i++) {
4404*4882a593Smuzhiyun DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
4405*4882a593Smuzhiyun
4406*4882a593Smuzhiyun if (threads == NULL) {
4407*4882a593Smuzhiyun fprintf(fp, "%s", "Error sorting output by nr_events!\n");
4408*4882a593Smuzhiyun return 0;
4409*4882a593Smuzhiyun }
4410*4882a593Smuzhiyun
4411*4882a593Smuzhiyun resort_rb__for_each_entry(nd, threads)
4412*4882a593Smuzhiyun printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
4413*4882a593Smuzhiyun
4414*4882a593Smuzhiyun resort_rb__delete(threads);
4415*4882a593Smuzhiyun }
4416*4882a593Smuzhiyun return printed;
4417*4882a593Smuzhiyun }
4418*4882a593Smuzhiyun
4419*4882a593Smuzhiyun static int trace__set_duration(const struct option *opt, const char *str,
4420*4882a593Smuzhiyun int unset __maybe_unused)
4421*4882a593Smuzhiyun {
4422*4882a593Smuzhiyun struct trace *trace = opt->value;
4423*4882a593Smuzhiyun
4424*4882a593Smuzhiyun trace->duration_filter = atof(str);
4425*4882a593Smuzhiyun return 0;
4426*4882a593Smuzhiyun }
4427*4882a593Smuzhiyun
4428*4882a593Smuzhiyun static int trace__set_filter_pids_from_option(const struct option *opt, const char *str,
4429*4882a593Smuzhiyun int unset __maybe_unused)
4430*4882a593Smuzhiyun {
4431*4882a593Smuzhiyun int ret = -1;
4432*4882a593Smuzhiyun size_t i;
4433*4882a593Smuzhiyun struct trace *trace = opt->value;
4434*4882a593Smuzhiyun /*
4435*4882a593Smuzhiyun * FIXME: introduce a intarray class, plain parse csv and create a
4436*4882a593Smuzhiyun * { int nr, int entries[] } struct...
4437*4882a593Smuzhiyun */
4438*4882a593Smuzhiyun struct intlist *list = intlist__new(str);
4439*4882a593Smuzhiyun
4440*4882a593Smuzhiyun if (list == NULL)
4441*4882a593Smuzhiyun return -1;
4442*4882a593Smuzhiyun
4443*4882a593Smuzhiyun i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
4444*4882a593Smuzhiyun trace->filter_pids.entries = calloc(i, sizeof(pid_t));
4445*4882a593Smuzhiyun
4446*4882a593Smuzhiyun if (trace->filter_pids.entries == NULL)
4447*4882a593Smuzhiyun goto out;
4448*4882a593Smuzhiyun
4449*4882a593Smuzhiyun trace->filter_pids.entries[0] = getpid();
4450*4882a593Smuzhiyun
4451*4882a593Smuzhiyun for (i = 1; i < trace->filter_pids.nr; ++i)
4452*4882a593Smuzhiyun trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
4453*4882a593Smuzhiyun
4454*4882a593Smuzhiyun intlist__delete(list);
4455*4882a593Smuzhiyun ret = 0;
4456*4882a593Smuzhiyun out:
4457*4882a593Smuzhiyun return ret;
4458*4882a593Smuzhiyun }
4459*4882a593Smuzhiyun
4460*4882a593Smuzhiyun static int trace__open_output(struct trace *trace, const char *filename)
4461*4882a593Smuzhiyun {
4462*4882a593Smuzhiyun struct stat st;
4463*4882a593Smuzhiyun
4464*4882a593Smuzhiyun if (!stat(filename, &st) && st.st_size) {
4465*4882a593Smuzhiyun char oldname[PATH_MAX];
4466*4882a593Smuzhiyun
4467*4882a593Smuzhiyun scnprintf(oldname, sizeof(oldname), "%s.old", filename);
4468*4882a593Smuzhiyun unlink(oldname);
4469*4882a593Smuzhiyun rename(filename, oldname);
4470*4882a593Smuzhiyun }
4471*4882a593Smuzhiyun
4472*4882a593Smuzhiyun trace->output = fopen(filename, "w");
4473*4882a593Smuzhiyun
4474*4882a593Smuzhiyun return trace->output == NULL ? -errno : 0;
4475*4882a593Smuzhiyun }
4476*4882a593Smuzhiyun
4477*4882a593Smuzhiyun static int parse_pagefaults(const struct option *opt, const char *str,
4478*4882a593Smuzhiyun int unset __maybe_unused)
4479*4882a593Smuzhiyun {
4480*4882a593Smuzhiyun int *trace_pgfaults = opt->value;
4481*4882a593Smuzhiyun
4482*4882a593Smuzhiyun if (strcmp(str, "all") == 0)
4483*4882a593Smuzhiyun *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
4484*4882a593Smuzhiyun else if (strcmp(str, "maj") == 0)
4485*4882a593Smuzhiyun *trace_pgfaults |= TRACE_PFMAJ;
4486*4882a593Smuzhiyun else if (strcmp(str, "min") == 0)
4487*4882a593Smuzhiyun *trace_pgfaults |= TRACE_PFMIN;
4488*4882a593Smuzhiyun else
4489*4882a593Smuzhiyun return -1;
4490*4882a593Smuzhiyun
4491*4882a593Smuzhiyun return 0;
4492*4882a593Smuzhiyun }
4493*4882a593Smuzhiyun
4494*4882a593Smuzhiyun static void evlist__set_default_evsel_handler(struct evlist *evlist, void *handler)
4495*4882a593Smuzhiyun {
4496*4882a593Smuzhiyun struct evsel *evsel;
4497*4882a593Smuzhiyun
4498*4882a593Smuzhiyun evlist__for_each_entry(evlist, evsel) {
4499*4882a593Smuzhiyun if (evsel->handler == NULL)
4500*4882a593Smuzhiyun evsel->handler = handler;
4501*4882a593Smuzhiyun }
4502*4882a593Smuzhiyun }
4503*4882a593Smuzhiyun
4504*4882a593Smuzhiyun static void evsel__set_syscall_arg_fmt(struct evsel *evsel, const char *name)
4505*4882a593Smuzhiyun {
4506*4882a593Smuzhiyun struct syscall_arg_fmt *fmt = evsel__syscall_arg_fmt(evsel);
4507*4882a593Smuzhiyun
4508*4882a593Smuzhiyun if (fmt) {
4509*4882a593Smuzhiyun struct syscall_fmt *scfmt = syscall_fmt__find(name);
4510*4882a593Smuzhiyun
4511*4882a593Smuzhiyun if (scfmt) {
4512*4882a593Smuzhiyun int skip = 0;
4513*4882a593Smuzhiyun
4514*4882a593Smuzhiyun if (strcmp(evsel->tp_format->format.fields->name, "__syscall_nr") == 0 ||
4515*4882a593Smuzhiyun strcmp(evsel->tp_format->format.fields->name, "nr") == 0)
4516*4882a593Smuzhiyun ++skip;
4517*4882a593Smuzhiyun
4518*4882a593Smuzhiyun memcpy(fmt + skip, scfmt->arg, (evsel->tp_format->format.nr_fields - skip) * sizeof(*fmt));
4519*4882a593Smuzhiyun }
4520*4882a593Smuzhiyun }
4521*4882a593Smuzhiyun }
4522*4882a593Smuzhiyun
4523*4882a593Smuzhiyun static int evlist__set_syscall_tp_fields(struct evlist *evlist)
4524*4882a593Smuzhiyun {
4525*4882a593Smuzhiyun struct evsel *evsel;
4526*4882a593Smuzhiyun
4527*4882a593Smuzhiyun evlist__for_each_entry(evlist, evsel) {
4528*4882a593Smuzhiyun if (evsel->priv || !evsel->tp_format)
4529*4882a593Smuzhiyun continue;
4530*4882a593Smuzhiyun
4531*4882a593Smuzhiyun if (strcmp(evsel->tp_format->system, "syscalls")) {
4532*4882a593Smuzhiyun evsel__init_tp_arg_scnprintf(evsel);
4533*4882a593Smuzhiyun continue;
4534*4882a593Smuzhiyun }
4535*4882a593Smuzhiyun
4536*4882a593Smuzhiyun if (evsel__init_syscall_tp(evsel))
4537*4882a593Smuzhiyun return -1;
4538*4882a593Smuzhiyun
4539*4882a593Smuzhiyun if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
4540*4882a593Smuzhiyun struct syscall_tp *sc = __evsel__syscall_tp(evsel);
4541*4882a593Smuzhiyun
4542*4882a593Smuzhiyun if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
4543*4882a593Smuzhiyun return -1;
4544*4882a593Smuzhiyun
4545*4882a593Smuzhiyun evsel__set_syscall_arg_fmt(evsel, evsel->tp_format->name + sizeof("sys_enter_") - 1);
4546*4882a593Smuzhiyun } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
4547*4882a593Smuzhiyun struct syscall_tp *sc = __evsel__syscall_tp(evsel);
4548*4882a593Smuzhiyun
4549*4882a593Smuzhiyun if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
4550*4882a593Smuzhiyun return -1;
4551*4882a593Smuzhiyun
4552*4882a593Smuzhiyun evsel__set_syscall_arg_fmt(evsel, evsel->tp_format->name + sizeof("sys_exit_") - 1);
4553*4882a593Smuzhiyun }
4554*4882a593Smuzhiyun }
4555*4882a593Smuzhiyun
4556*4882a593Smuzhiyun return 0;
4557*4882a593Smuzhiyun }
4558*4882a593Smuzhiyun
4559*4882a593Smuzhiyun /*
4560*4882a593Smuzhiyun * XXX: Hackish, just splitting the combined -e+--event (syscalls
4561*4882a593Smuzhiyun * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
4562*4882a593Smuzhiyun * existing facilities unchanged (trace->ev_qualifier + parse_options()).
4563*4882a593Smuzhiyun *
4564*4882a593Smuzhiyun * It'd be better to introduce a parse_options() variant that would return a
4565*4882a593Smuzhiyun * list with the terms it didn't match to an event...
4566*4882a593Smuzhiyun */
4567*4882a593Smuzhiyun static int trace__parse_events_option(const struct option *opt, const char *str,
4568*4882a593Smuzhiyun int unset __maybe_unused)
4569*4882a593Smuzhiyun {
4570*4882a593Smuzhiyun struct trace *trace = (struct trace *)opt->value;
4571*4882a593Smuzhiyun const char *s = str;
4572*4882a593Smuzhiyun char *sep = NULL, *lists[2] = { NULL, NULL, };
4573*4882a593Smuzhiyun int len = strlen(str) + 1, err = -1, list, idx;
4574*4882a593Smuzhiyun char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
4575*4882a593Smuzhiyun char group_name[PATH_MAX];
4576*4882a593Smuzhiyun struct syscall_fmt *fmt;
4577*4882a593Smuzhiyun
4578*4882a593Smuzhiyun if (strace_groups_dir == NULL)
4579*4882a593Smuzhiyun return -1;
4580*4882a593Smuzhiyun
4581*4882a593Smuzhiyun if (*s == '!') {
4582*4882a593Smuzhiyun ++s;
4583*4882a593Smuzhiyun trace->not_ev_qualifier = true;
4584*4882a593Smuzhiyun }
4585*4882a593Smuzhiyun
4586*4882a593Smuzhiyun while (1) {
4587*4882a593Smuzhiyun if ((sep = strchr(s, ',')) != NULL)
4588*4882a593Smuzhiyun *sep = '\0';
4589*4882a593Smuzhiyun
4590*4882a593Smuzhiyun list = 0;
4591*4882a593Smuzhiyun if (syscalltbl__id(trace->sctbl, s) >= 0 ||
4592*4882a593Smuzhiyun syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
4593*4882a593Smuzhiyun list = 1;
4594*4882a593Smuzhiyun goto do_concat;
4595*4882a593Smuzhiyun }
4596*4882a593Smuzhiyun
4597*4882a593Smuzhiyun fmt = syscall_fmt__find_by_alias(s);
4598*4882a593Smuzhiyun if (fmt != NULL) {
4599*4882a593Smuzhiyun list = 1;
4600*4882a593Smuzhiyun s = fmt->name;
4601*4882a593Smuzhiyun } else {
4602*4882a593Smuzhiyun path__join(group_name, sizeof(group_name), strace_groups_dir, s);
4603*4882a593Smuzhiyun if (access(group_name, R_OK) == 0)
4604*4882a593Smuzhiyun list = 1;
4605*4882a593Smuzhiyun }
4606*4882a593Smuzhiyun do_concat:
4607*4882a593Smuzhiyun if (lists[list]) {
4608*4882a593Smuzhiyun sprintf(lists[list] + strlen(lists[list]), ",%s", s);
4609*4882a593Smuzhiyun } else {
4610*4882a593Smuzhiyun lists[list] = malloc(len);
4611*4882a593Smuzhiyun if (lists[list] == NULL)
4612*4882a593Smuzhiyun goto out;
4613*4882a593Smuzhiyun strcpy(lists[list], s);
4614*4882a593Smuzhiyun }
4615*4882a593Smuzhiyun
4616*4882a593Smuzhiyun if (!sep)
4617*4882a593Smuzhiyun break;
4618*4882a593Smuzhiyun
4619*4882a593Smuzhiyun *sep = ',';
4620*4882a593Smuzhiyun s = sep + 1;
4621*4882a593Smuzhiyun }
4622*4882a593Smuzhiyun
4623*4882a593Smuzhiyun if (lists[1] != NULL) {
4624*4882a593Smuzhiyun struct strlist_config slist_config = {
4625*4882a593Smuzhiyun .dirname = strace_groups_dir,
4626*4882a593Smuzhiyun };
4627*4882a593Smuzhiyun
4628*4882a593Smuzhiyun trace->ev_qualifier = strlist__new(lists[1], &slist_config);
4629*4882a593Smuzhiyun if (trace->ev_qualifier == NULL) {
4630*4882a593Smuzhiyun fputs("Not enough memory to parse event qualifier", trace->output);
4631*4882a593Smuzhiyun goto out;
4632*4882a593Smuzhiyun }
4633*4882a593Smuzhiyun
4634*4882a593Smuzhiyun if (trace__validate_ev_qualifier(trace))
4635*4882a593Smuzhiyun goto out;
4636*4882a593Smuzhiyun trace->trace_syscalls = true;
4637*4882a593Smuzhiyun }
4638*4882a593Smuzhiyun
4639*4882a593Smuzhiyun err = 0;
4640*4882a593Smuzhiyun
4641*4882a593Smuzhiyun if (lists[0]) {
4642*4882a593Smuzhiyun struct option o = {
4643*4882a593Smuzhiyun .value = &trace->evlist,
4644*4882a593Smuzhiyun };
4645*4882a593Smuzhiyun err = parse_events_option(&o, lists[0], 0);
4646*4882a593Smuzhiyun }
4647*4882a593Smuzhiyun out:
4648*4882a593Smuzhiyun if (sep)
4649*4882a593Smuzhiyun *sep = ',';
4650*4882a593Smuzhiyun
4651*4882a593Smuzhiyun return err;
4652*4882a593Smuzhiyun }
4653*4882a593Smuzhiyun
4654*4882a593Smuzhiyun static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
4655*4882a593Smuzhiyun {
4656*4882a593Smuzhiyun struct trace *trace = opt->value;
4657*4882a593Smuzhiyun
4658*4882a593Smuzhiyun if (!list_empty(&trace->evlist->core.entries)) {
4659*4882a593Smuzhiyun struct option o = {
4660*4882a593Smuzhiyun .value = &trace->evlist,
4661*4882a593Smuzhiyun };
4662*4882a593Smuzhiyun return parse_cgroups(&o, str, unset);
4663*4882a593Smuzhiyun }
4664*4882a593Smuzhiyun trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
4665*4882a593Smuzhiyun
4666*4882a593Smuzhiyun return 0;
4667*4882a593Smuzhiyun }
4668*4882a593Smuzhiyun
4669*4882a593Smuzhiyun static int trace__config(const char *var, const char *value, void *arg)
4670*4882a593Smuzhiyun {
4671*4882a593Smuzhiyun struct trace *trace = arg;
4672*4882a593Smuzhiyun int err = 0;
4673*4882a593Smuzhiyun
4674*4882a593Smuzhiyun if (!strcmp(var, "trace.add_events")) {
4675*4882a593Smuzhiyun trace->perfconfig_events = strdup(value);
4676*4882a593Smuzhiyun if (trace->perfconfig_events == NULL) {
4677*4882a593Smuzhiyun pr_err("Not enough memory for %s\n", "trace.add_events");
4678*4882a593Smuzhiyun return -1;
4679*4882a593Smuzhiyun }
4680*4882a593Smuzhiyun } else if (!strcmp(var, "trace.show_timestamp")) {
4681*4882a593Smuzhiyun trace->show_tstamp = perf_config_bool(var, value);
4682*4882a593Smuzhiyun } else if (!strcmp(var, "trace.show_duration")) {
4683*4882a593Smuzhiyun trace->show_duration = perf_config_bool(var, value);
4684*4882a593Smuzhiyun } else if (!strcmp(var, "trace.show_arg_names")) {
4685*4882a593Smuzhiyun trace->show_arg_names = perf_config_bool(var, value);
4686*4882a593Smuzhiyun if (!trace->show_arg_names)
4687*4882a593Smuzhiyun trace->show_zeros = true;
4688*4882a593Smuzhiyun } else if (!strcmp(var, "trace.show_zeros")) {
4689*4882a593Smuzhiyun bool new_show_zeros = perf_config_bool(var, value);
4690*4882a593Smuzhiyun if (!trace->show_arg_names && !new_show_zeros) {
4691*4882a593Smuzhiyun pr_warning("trace.show_zeros has to be set when trace.show_arg_names=no\n");
4692*4882a593Smuzhiyun goto out;
4693*4882a593Smuzhiyun }
4694*4882a593Smuzhiyun trace->show_zeros = new_show_zeros;
4695*4882a593Smuzhiyun } else if (!strcmp(var, "trace.show_prefix")) {
4696*4882a593Smuzhiyun trace->show_string_prefix = perf_config_bool(var, value);
4697*4882a593Smuzhiyun } else if (!strcmp(var, "trace.no_inherit")) {
4698*4882a593Smuzhiyun trace->opts.no_inherit = perf_config_bool(var, value);
4699*4882a593Smuzhiyun } else if (!strcmp(var, "trace.args_alignment")) {
4700*4882a593Smuzhiyun int args_alignment = 0;
4701*4882a593Smuzhiyun if (perf_config_int(&args_alignment, var, value) == 0)
4702*4882a593Smuzhiyun trace->args_alignment = args_alignment;
4703*4882a593Smuzhiyun } else if (!strcmp(var, "trace.tracepoint_beautifiers")) {
4704*4882a593Smuzhiyun if (strcasecmp(value, "libtraceevent") == 0)
4705*4882a593Smuzhiyun trace->libtraceevent_print = true;
4706*4882a593Smuzhiyun else if (strcasecmp(value, "libbeauty") == 0)
4707*4882a593Smuzhiyun trace->libtraceevent_print = false;
4708*4882a593Smuzhiyun }
4709*4882a593Smuzhiyun out:
4710*4882a593Smuzhiyun return err;
4711*4882a593Smuzhiyun }
4712*4882a593Smuzhiyun
4713*4882a593Smuzhiyun int cmd_trace(int argc, const char **argv)
4714*4882a593Smuzhiyun {
4715*4882a593Smuzhiyun const char *trace_usage[] = {
4716*4882a593Smuzhiyun "perf trace [<options>] [<command>]",
4717*4882a593Smuzhiyun "perf trace [<options>] -- <command> [<options>]",
4718*4882a593Smuzhiyun "perf trace record [<options>] [<command>]",
4719*4882a593Smuzhiyun "perf trace record [<options>] -- <command> [<options>]",
4720*4882a593Smuzhiyun NULL
4721*4882a593Smuzhiyun };
4722*4882a593Smuzhiyun struct trace trace = {
4723*4882a593Smuzhiyun .opts = {
4724*4882a593Smuzhiyun .target = {
4725*4882a593Smuzhiyun .uid = UINT_MAX,
4726*4882a593Smuzhiyun .uses_mmap = true,
4727*4882a593Smuzhiyun },
4728*4882a593Smuzhiyun .user_freq = UINT_MAX,
4729*4882a593Smuzhiyun .user_interval = ULLONG_MAX,
4730*4882a593Smuzhiyun .no_buffering = true,
4731*4882a593Smuzhiyun .mmap_pages = UINT_MAX,
4732*4882a593Smuzhiyun },
4733*4882a593Smuzhiyun .output = stderr,
4734*4882a593Smuzhiyun .show_comm = true,
4735*4882a593Smuzhiyun .show_tstamp = true,
4736*4882a593Smuzhiyun .show_duration = true,
4737*4882a593Smuzhiyun .show_arg_names = true,
4738*4882a593Smuzhiyun .args_alignment = 70,
4739*4882a593Smuzhiyun .trace_syscalls = false,
4740*4882a593Smuzhiyun .kernel_syscallchains = false,
4741*4882a593Smuzhiyun .max_stack = UINT_MAX,
4742*4882a593Smuzhiyun .max_events = ULONG_MAX,
4743*4882a593Smuzhiyun };
4744*4882a593Smuzhiyun const char *map_dump_str = NULL;
4745*4882a593Smuzhiyun const char *output_name = NULL;
4746*4882a593Smuzhiyun const struct option trace_options[] = {
4747*4882a593Smuzhiyun OPT_CALLBACK('e', "event", &trace, "event",
4748*4882a593Smuzhiyun "event/syscall selector. use 'perf list' to list available events",
4749*4882a593Smuzhiyun trace__parse_events_option),
4750*4882a593Smuzhiyun OPT_CALLBACK(0, "filter", &trace.evlist, "filter",
4751*4882a593Smuzhiyun "event filter", parse_filter),
4752*4882a593Smuzhiyun OPT_BOOLEAN(0, "comm", &trace.show_comm,
4753*4882a593Smuzhiyun "show the thread COMM next to its id"),
4754*4882a593Smuzhiyun OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
4755*4882a593Smuzhiyun OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
4756*4882a593Smuzhiyun trace__parse_events_option),
4757*4882a593Smuzhiyun OPT_STRING('o', "output", &output_name, "file", "output file name"),
4758*4882a593Smuzhiyun OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
4759*4882a593Smuzhiyun OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
4760*4882a593Smuzhiyun "trace events on existing process id"),
4761*4882a593Smuzhiyun OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
4762*4882a593Smuzhiyun "trace events on existing thread id"),
4763*4882a593Smuzhiyun OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
4764*4882a593Smuzhiyun "pids to filter (by the kernel)", trace__set_filter_pids_from_option),
4765*4882a593Smuzhiyun OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
4766*4882a593Smuzhiyun "system-wide collection from all CPUs"),
4767*4882a593Smuzhiyun OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
4768*4882a593Smuzhiyun "list of cpus to monitor"),
4769*4882a593Smuzhiyun OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
4770*4882a593Smuzhiyun "child tasks do not inherit counters"),
4771*4882a593Smuzhiyun OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
4772*4882a593Smuzhiyun "number of mmap data pages",
4773*4882a593Smuzhiyun perf_evlist__parse_mmap_pages),
4774*4882a593Smuzhiyun OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
4775*4882a593Smuzhiyun "user to profile"),
4776*4882a593Smuzhiyun OPT_CALLBACK(0, "duration", &trace, "float",
4777*4882a593Smuzhiyun "show only events with duration > N.M ms",
4778*4882a593Smuzhiyun trace__set_duration),
4779*4882a593Smuzhiyun #ifdef HAVE_LIBBPF_SUPPORT
4780*4882a593Smuzhiyun OPT_STRING(0, "map-dump", &map_dump_str, "BPF map", "BPF map to periodically dump"),
4781*4882a593Smuzhiyun #endif
4782*4882a593Smuzhiyun OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
4783*4882a593Smuzhiyun OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4784*4882a593Smuzhiyun OPT_BOOLEAN('T', "time", &trace.full_time,
4785*4882a593Smuzhiyun "Show full timestamp, not time relative to first start"),
4786*4882a593Smuzhiyun OPT_BOOLEAN(0, "failure", &trace.failure_only,
4787*4882a593Smuzhiyun "Show only syscalls that failed"),
4788*4882a593Smuzhiyun OPT_BOOLEAN('s', "summary", &trace.summary_only,
4789*4882a593Smuzhiyun "Show only syscall summary with statistics"),
4790*4882a593Smuzhiyun OPT_BOOLEAN('S', "with-summary", &trace.summary,
4791*4882a593Smuzhiyun "Show all syscalls and summary with statistics"),
4792*4882a593Smuzhiyun OPT_BOOLEAN(0, "errno-summary", &trace.errno_summary,
4793*4882a593Smuzhiyun "Show errno stats per syscall, use with -s or -S"),
4794*4882a593Smuzhiyun OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
4795*4882a593Smuzhiyun "Trace pagefaults", parse_pagefaults, "maj"),
4796*4882a593Smuzhiyun OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
4797*4882a593Smuzhiyun OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
4798*4882a593Smuzhiyun OPT_CALLBACK(0, "call-graph", &trace.opts,
4799*4882a593Smuzhiyun "record_mode[,record_size]", record_callchain_help,
4800*4882a593Smuzhiyun &record_parse_callchain_opt),
4801*4882a593Smuzhiyun OPT_BOOLEAN(0, "libtraceevent_print", &trace.libtraceevent_print,
4802*4882a593Smuzhiyun "Use libtraceevent to print the tracepoint arguments."),
4803*4882a593Smuzhiyun OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
4804*4882a593Smuzhiyun "Show the kernel callchains on the syscall exit path"),
4805*4882a593Smuzhiyun OPT_ULONG(0, "max-events", &trace.max_events,
4806*4882a593Smuzhiyun "Set the maximum number of events to print, exit after that is reached. "),
4807*4882a593Smuzhiyun OPT_UINTEGER(0, "min-stack", &trace.min_stack,
4808*4882a593Smuzhiyun "Set the minimum stack depth when parsing the callchain, "
4809*4882a593Smuzhiyun "anything below the specified depth will be ignored."),
4810*4882a593Smuzhiyun OPT_UINTEGER(0, "max-stack", &trace.max_stack,
4811*4882a593Smuzhiyun "Set the maximum stack depth when parsing the callchain, "
4812*4882a593Smuzhiyun "anything beyond the specified depth will be ignored. "
4813*4882a593Smuzhiyun "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
4814*4882a593Smuzhiyun OPT_BOOLEAN(0, "sort-events", &trace.sort_events,
4815*4882a593Smuzhiyun "Sort batch of events before processing, use if getting out of order events"),
4816*4882a593Smuzhiyun OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
4817*4882a593Smuzhiyun "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
4818*4882a593Smuzhiyun OPT_UINTEGER(0, "proc-map-timeout", &proc_map_timeout,
4819*4882a593Smuzhiyun "per thread proc mmap processing timeout in ms"),
4820*4882a593Smuzhiyun OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
4821*4882a593Smuzhiyun trace__parse_cgroups),
4822*4882a593Smuzhiyun OPT_INTEGER('D', "delay", &trace.opts.initial_delay,
4823*4882a593Smuzhiyun "ms to wait before starting measurement after program "
4824*4882a593Smuzhiyun "start"),
4825*4882a593Smuzhiyun OPTS_EVSWITCH(&trace.evswitch),
4826*4882a593Smuzhiyun OPT_END()
4827*4882a593Smuzhiyun };
4828*4882a593Smuzhiyun bool __maybe_unused max_stack_user_set = true;
4829*4882a593Smuzhiyun bool mmap_pages_user_set = true;
4830*4882a593Smuzhiyun struct evsel *evsel;
4831*4882a593Smuzhiyun const char * const trace_subcommands[] = { "record", NULL };
4832*4882a593Smuzhiyun int err = -1;
4833*4882a593Smuzhiyun char bf[BUFSIZ];
4834*4882a593Smuzhiyun
4835*4882a593Smuzhiyun signal(SIGSEGV, sighandler_dump_stack);
4836*4882a593Smuzhiyun signal(SIGFPE, sighandler_dump_stack);
4837*4882a593Smuzhiyun
4838*4882a593Smuzhiyun trace.evlist = evlist__new();
4839*4882a593Smuzhiyun trace.sctbl = syscalltbl__new();
4840*4882a593Smuzhiyun
4841*4882a593Smuzhiyun if (trace.evlist == NULL || trace.sctbl == NULL) {
4842*4882a593Smuzhiyun pr_err("Not enough memory to run!\n");
4843*4882a593Smuzhiyun err = -ENOMEM;
4844*4882a593Smuzhiyun goto out;
4845*4882a593Smuzhiyun }
4846*4882a593Smuzhiyun
4847*4882a593Smuzhiyun /*
4848*4882a593Smuzhiyun * Parsing .perfconfig may entail creating a BPF event, that may need
4849*4882a593Smuzhiyun * to create BPF maps, so bump RLIM_MEMLOCK as the default 64K setting
4850*4882a593Smuzhiyun * is too small. This affects just this process, not touching the
4851*4882a593Smuzhiyun * global setting. If it fails we'll get something in 'perf trace -v'
4852*4882a593Smuzhiyun * to help diagnose the problem.
4853*4882a593Smuzhiyun */
4854*4882a593Smuzhiyun rlimit__bump_memlock();
4855*4882a593Smuzhiyun
4856*4882a593Smuzhiyun err = perf_config(trace__config, &trace);
4857*4882a593Smuzhiyun if (err)
4858*4882a593Smuzhiyun goto out;
4859*4882a593Smuzhiyun
4860*4882a593Smuzhiyun argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
4861*4882a593Smuzhiyun trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
4862*4882a593Smuzhiyun
4863*4882a593Smuzhiyun /*
4864*4882a593Smuzhiyun * Here we already passed thru trace__parse_events_option() and it has
4865*4882a593Smuzhiyun * already figured out if -e syscall_name, if not but if --event
4866*4882a593Smuzhiyun * foo:bar was used, the user is interested _just_ in those, say,
4867*4882a593Smuzhiyun * tracepoint events, not in the strace-like syscall-name-based mode.
4868*4882a593Smuzhiyun *
4869*4882a593Smuzhiyun * This is important because we need to check if strace-like mode is
4870*4882a593Smuzhiyun * needed to decided if we should filter out the eBPF
4871*4882a593Smuzhiyun * __augmented_syscalls__ code, if it is in the mix, say, via
4872*4882a593Smuzhiyun * .perfconfig trace.add_events, and filter those out.
4873*4882a593Smuzhiyun */
4874*4882a593Smuzhiyun if (!trace.trace_syscalls && !trace.trace_pgfaults &&
4875*4882a593Smuzhiyun trace.evlist->core.nr_entries == 0 /* Was --events used? */) {
4876*4882a593Smuzhiyun trace.trace_syscalls = true;
4877*4882a593Smuzhiyun }
4878*4882a593Smuzhiyun /*
4879*4882a593Smuzhiyun * Now that we have --verbose figured out, lets see if we need to parse
4880*4882a593Smuzhiyun * events from .perfconfig, so that if those events fail parsing, say some
4881*4882a593Smuzhiyun * BPF program fails, then we'll be able to use --verbose to see what went
4882*4882a593Smuzhiyun * wrong in more detail.
4883*4882a593Smuzhiyun */
4884*4882a593Smuzhiyun if (trace.perfconfig_events != NULL) {
4885*4882a593Smuzhiyun struct parse_events_error parse_err;
4886*4882a593Smuzhiyun
4887*4882a593Smuzhiyun bzero(&parse_err, sizeof(parse_err));
4888*4882a593Smuzhiyun err = parse_events(trace.evlist, trace.perfconfig_events, &parse_err);
4889*4882a593Smuzhiyun if (err) {
4890*4882a593Smuzhiyun parse_events_print_error(&parse_err, trace.perfconfig_events);
4891*4882a593Smuzhiyun goto out;
4892*4882a593Smuzhiyun }
4893*4882a593Smuzhiyun }
4894*4882a593Smuzhiyun
4895*4882a593Smuzhiyun if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
4896*4882a593Smuzhiyun usage_with_options_msg(trace_usage, trace_options,
4897*4882a593Smuzhiyun "cgroup monitoring only available in system-wide mode");
4898*4882a593Smuzhiyun }
4899*4882a593Smuzhiyun
4900*4882a593Smuzhiyun evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__");
4901*4882a593Smuzhiyun if (IS_ERR(evsel)) {
4902*4882a593Smuzhiyun bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf));
4903*4882a593Smuzhiyun pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf);
4904*4882a593Smuzhiyun goto out;
4905*4882a593Smuzhiyun }
4906*4882a593Smuzhiyun
4907*4882a593Smuzhiyun if (evsel) {
4908*4882a593Smuzhiyun trace.syscalls.events.augmented = evsel;
4909*4882a593Smuzhiyun
4910*4882a593Smuzhiyun evsel = perf_evlist__find_tracepoint_by_name(trace.evlist, "raw_syscalls:sys_enter");
4911*4882a593Smuzhiyun if (evsel == NULL) {
4912*4882a593Smuzhiyun pr_err("ERROR: raw_syscalls:sys_enter not found in the augmented BPF object\n");
4913*4882a593Smuzhiyun goto out;
4914*4882a593Smuzhiyun }
4915*4882a593Smuzhiyun
4916*4882a593Smuzhiyun if (evsel->bpf_obj == NULL) {
4917*4882a593Smuzhiyun pr_err("ERROR: raw_syscalls:sys_enter not associated to a BPF object\n");
4918*4882a593Smuzhiyun goto out;
4919*4882a593Smuzhiyun }
4920*4882a593Smuzhiyun
4921*4882a593Smuzhiyun trace.bpf_obj = evsel->bpf_obj;
4922*4882a593Smuzhiyun
4923*4882a593Smuzhiyun /*
4924*4882a593Smuzhiyun * If we have _just_ the augmenter event but don't have a
4925*4882a593Smuzhiyun * explicit --syscalls, then assume we want all strace-like
4926*4882a593Smuzhiyun * syscalls:
4927*4882a593Smuzhiyun */
4928*4882a593Smuzhiyun if (!trace.trace_syscalls && trace__only_augmented_syscalls_evsels(&trace))
4929*4882a593Smuzhiyun trace.trace_syscalls = true;
4930*4882a593Smuzhiyun /*
4931*4882a593Smuzhiyun * So, if we have a syscall augmenter, but trace_syscalls, aka
4932*4882a593Smuzhiyun * strace-like syscall tracing is not set, then we need to trow
4933*4882a593Smuzhiyun * away the augmenter, i.e. all the events that were created
4934*4882a593Smuzhiyun * from that BPF object file.
4935*4882a593Smuzhiyun *
4936*4882a593Smuzhiyun * This is more to fix the current .perfconfig trace.add_events
4937*4882a593Smuzhiyun * style of setting up the strace-like eBPF based syscall point
4938*4882a593Smuzhiyun * payload augmenter.
4939*4882a593Smuzhiyun *
4940*4882a593Smuzhiyun * All this complexity will be avoided by adding an alternative
4941*4882a593Smuzhiyun * to trace.add_events in the form of
4942*4882a593Smuzhiyun * trace.bpf_augmented_syscalls, that will be only parsed if we
4943*4882a593Smuzhiyun * need it.
4944*4882a593Smuzhiyun *
4945*4882a593Smuzhiyun * .perfconfig trace.add_events is still useful if we want, for
4946*4882a593Smuzhiyun * instance, have msr_write.msr in some .perfconfig profile based
4947*4882a593Smuzhiyun * 'perf trace --config determinism.profile' mode, where for some
4948*4882a593Smuzhiyun * particular goal/workload type we want a set of events and
4949*4882a593Smuzhiyun * output mode (with timings, etc) instead of having to add
4950*4882a593Smuzhiyun * all via the command line.
4951*4882a593Smuzhiyun *
4952*4882a593Smuzhiyun * Also --config to specify an alternate .perfconfig file needs
4953*4882a593Smuzhiyun * to be implemented.
4954*4882a593Smuzhiyun */
4955*4882a593Smuzhiyun if (!trace.trace_syscalls) {
4956*4882a593Smuzhiyun trace__delete_augmented_syscalls(&trace);
4957*4882a593Smuzhiyun } else {
4958*4882a593Smuzhiyun trace__set_bpf_map_filtered_pids(&trace);
4959*4882a593Smuzhiyun trace__set_bpf_map_syscalls(&trace);
4960*4882a593Smuzhiyun trace.syscalls.unaugmented_prog = trace__find_bpf_program_by_title(&trace, "!raw_syscalls:unaugmented");
4961*4882a593Smuzhiyun }
4962*4882a593Smuzhiyun }
4963*4882a593Smuzhiyun
4964*4882a593Smuzhiyun err = bpf__setup_stdout(trace.evlist);
4965*4882a593Smuzhiyun if (err) {
4966*4882a593Smuzhiyun bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
4967*4882a593Smuzhiyun pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
4968*4882a593Smuzhiyun goto out;
4969*4882a593Smuzhiyun }
4970*4882a593Smuzhiyun
4971*4882a593Smuzhiyun err = -1;
4972*4882a593Smuzhiyun
4973*4882a593Smuzhiyun if (map_dump_str) {
4974*4882a593Smuzhiyun trace.dump.map = trace__find_bpf_map_by_name(&trace, map_dump_str);
4975*4882a593Smuzhiyun if (trace.dump.map == NULL) {
4976*4882a593Smuzhiyun pr_err("ERROR: BPF map \"%s\" not found\n", map_dump_str);
4977*4882a593Smuzhiyun goto out;
4978*4882a593Smuzhiyun }
4979*4882a593Smuzhiyun }
4980*4882a593Smuzhiyun
4981*4882a593Smuzhiyun if (trace.trace_pgfaults) {
4982*4882a593Smuzhiyun trace.opts.sample_address = true;
4983*4882a593Smuzhiyun trace.opts.sample_time = true;
4984*4882a593Smuzhiyun }
4985*4882a593Smuzhiyun
4986*4882a593Smuzhiyun if (trace.opts.mmap_pages == UINT_MAX)
4987*4882a593Smuzhiyun mmap_pages_user_set = false;
4988*4882a593Smuzhiyun
4989*4882a593Smuzhiyun if (trace.max_stack == UINT_MAX) {
4990*4882a593Smuzhiyun trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
4991*4882a593Smuzhiyun max_stack_user_set = false;
4992*4882a593Smuzhiyun }
4993*4882a593Smuzhiyun
4994*4882a593Smuzhiyun #ifdef HAVE_DWARF_UNWIND_SUPPORT
4995*4882a593Smuzhiyun if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
4996*4882a593Smuzhiyun record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
4997*4882a593Smuzhiyun }
4998*4882a593Smuzhiyun #endif
4999*4882a593Smuzhiyun
5000*4882a593Smuzhiyun if (callchain_param.enabled) {
5001*4882a593Smuzhiyun if (!mmap_pages_user_set && geteuid() == 0)
5002*4882a593Smuzhiyun trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
5003*4882a593Smuzhiyun
5004*4882a593Smuzhiyun symbol_conf.use_callchain = true;
5005*4882a593Smuzhiyun }
5006*4882a593Smuzhiyun
5007*4882a593Smuzhiyun if (trace.evlist->core.nr_entries > 0) {
5008*4882a593Smuzhiyun evlist__set_default_evsel_handler(trace.evlist, trace__event_handler);
5009*4882a593Smuzhiyun if (evlist__set_syscall_tp_fields(trace.evlist)) {
5010*4882a593Smuzhiyun perror("failed to set syscalls:* tracepoint fields");
5011*4882a593Smuzhiyun goto out;
5012*4882a593Smuzhiyun }
5013*4882a593Smuzhiyun }
5014*4882a593Smuzhiyun
5015*4882a593Smuzhiyun if (trace.sort_events) {
5016*4882a593Smuzhiyun ordered_events__init(&trace.oe.data, ordered_events__deliver_event, &trace);
5017*4882a593Smuzhiyun ordered_events__set_copy_on_queue(&trace.oe.data, true);
5018*4882a593Smuzhiyun }
5019*4882a593Smuzhiyun
5020*4882a593Smuzhiyun /*
5021*4882a593Smuzhiyun * If we are augmenting syscalls, then combine what we put in the
5022*4882a593Smuzhiyun * __augmented_syscalls__ BPF map with what is in the
5023*4882a593Smuzhiyun * syscalls:sys_exit_FOO tracepoints, i.e. just like we do without BPF,
5024*4882a593Smuzhiyun * combining raw_syscalls:sys_enter with raw_syscalls:sys_exit.
5025*4882a593Smuzhiyun *
5026*4882a593Smuzhiyun * We'll switch to look at two BPF maps, one for sys_enter and the
5027*4882a593Smuzhiyun * other for sys_exit when we start augmenting the sys_exit paths with
5028*4882a593Smuzhiyun * buffers that are being copied from kernel to userspace, think 'read'
5029*4882a593Smuzhiyun * syscall.
5030*4882a593Smuzhiyun */
5031*4882a593Smuzhiyun if (trace.syscalls.events.augmented) {
5032*4882a593Smuzhiyun evlist__for_each_entry(trace.evlist, evsel) {
5033*4882a593Smuzhiyun bool raw_syscalls_sys_exit = strcmp(evsel__name(evsel), "raw_syscalls:sys_exit") == 0;
5034*4882a593Smuzhiyun
5035*4882a593Smuzhiyun if (raw_syscalls_sys_exit) {
5036*4882a593Smuzhiyun trace.raw_augmented_syscalls = true;
5037*4882a593Smuzhiyun goto init_augmented_syscall_tp;
5038*4882a593Smuzhiyun }
5039*4882a593Smuzhiyun
5040*4882a593Smuzhiyun if (trace.syscalls.events.augmented->priv == NULL &&
5041*4882a593Smuzhiyun strstr(evsel__name(evsel), "syscalls:sys_enter")) {
5042*4882a593Smuzhiyun struct evsel *augmented = trace.syscalls.events.augmented;
5043*4882a593Smuzhiyun if (evsel__init_augmented_syscall_tp(augmented, evsel) ||
5044*4882a593Smuzhiyun evsel__init_augmented_syscall_tp_args(augmented))
5045*4882a593Smuzhiyun goto out;
5046*4882a593Smuzhiyun /*
5047*4882a593Smuzhiyun * Augmented is __augmented_syscalls__ BPF_OUTPUT event
5048*4882a593Smuzhiyun * Above we made sure we can get from the payload the tp fields
5049*4882a593Smuzhiyun * that we get from syscalls:sys_enter tracefs format file.
5050*4882a593Smuzhiyun */
5051*4882a593Smuzhiyun augmented->handler = trace__sys_enter;
5052*4882a593Smuzhiyun /*
5053*4882a593Smuzhiyun * Now we do the same for the *syscalls:sys_enter event so that
5054*4882a593Smuzhiyun * if we handle it directly, i.e. if the BPF prog returns 0 so
5055*4882a593Smuzhiyun * as not to filter it, then we'll handle it just like we would
5056*4882a593Smuzhiyun * for the BPF_OUTPUT one:
5057*4882a593Smuzhiyun */
5058*4882a593Smuzhiyun if (evsel__init_augmented_syscall_tp(evsel, evsel) ||
5059*4882a593Smuzhiyun evsel__init_augmented_syscall_tp_args(evsel))
5060*4882a593Smuzhiyun goto out;
5061*4882a593Smuzhiyun evsel->handler = trace__sys_enter;
5062*4882a593Smuzhiyun }
5063*4882a593Smuzhiyun
5064*4882a593Smuzhiyun if (strstarts(evsel__name(evsel), "syscalls:sys_exit_")) {
5065*4882a593Smuzhiyun struct syscall_tp *sc;
5066*4882a593Smuzhiyun init_augmented_syscall_tp:
5067*4882a593Smuzhiyun if (evsel__init_augmented_syscall_tp(evsel, evsel))
5068*4882a593Smuzhiyun goto out;
5069*4882a593Smuzhiyun sc = __evsel__syscall_tp(evsel);
5070*4882a593Smuzhiyun /*
5071*4882a593Smuzhiyun * For now with BPF raw_augmented we hook into
5072*4882a593Smuzhiyun * raw_syscalls:sys_enter and there we get all
5073*4882a593Smuzhiyun * 6 syscall args plus the tracepoint common
5074*4882a593Smuzhiyun * fields and the syscall_nr (another long).
5075*4882a593Smuzhiyun * So we check if that is the case and if so
5076*4882a593Smuzhiyun * don't look after the sc->args_size but
5077*4882a593Smuzhiyun * always after the full raw_syscalls:sys_enter
5078*4882a593Smuzhiyun * payload, which is fixed.
5079*4882a593Smuzhiyun *
5080*4882a593Smuzhiyun * We'll revisit this later to pass
5081*4882a593Smuzhiyun * s->args_size to the BPF augmenter (now
5082*4882a593Smuzhiyun * tools/perf/examples/bpf/augmented_raw_syscalls.c,
5083*4882a593Smuzhiyun * so that it copies only what we need for each
5084*4882a593Smuzhiyun * syscall, like what happens when we use
5085*4882a593Smuzhiyun * syscalls:sys_enter_NAME, so that we reduce
5086*4882a593Smuzhiyun * the kernel/userspace traffic to just what is
5087*4882a593Smuzhiyun * needed for each syscall.
5088*4882a593Smuzhiyun */
5089*4882a593Smuzhiyun if (trace.raw_augmented_syscalls)
5090*4882a593Smuzhiyun trace.raw_augmented_syscalls_args_size = (6 + 1) * sizeof(long) + sc->id.offset;
5091*4882a593Smuzhiyun evsel__init_augmented_syscall_tp_ret(evsel);
5092*4882a593Smuzhiyun evsel->handler = trace__sys_exit;
5093*4882a593Smuzhiyun }
5094*4882a593Smuzhiyun }
5095*4882a593Smuzhiyun }
5096*4882a593Smuzhiyun
5097*4882a593Smuzhiyun if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
5098*4882a593Smuzhiyun return trace__record(&trace, argc-1, &argv[1]);
5099*4882a593Smuzhiyun
5100*4882a593Smuzhiyun /* Using just --errno-summary will trigger --summary */
5101*4882a593Smuzhiyun if (trace.errno_summary && !trace.summary && !trace.summary_only)
5102*4882a593Smuzhiyun trace.summary_only = true;
5103*4882a593Smuzhiyun
5104*4882a593Smuzhiyun /* summary_only implies summary option, but don't overwrite summary if set */
5105*4882a593Smuzhiyun if (trace.summary_only)
5106*4882a593Smuzhiyun trace.summary = trace.summary_only;
5107*4882a593Smuzhiyun
5108*4882a593Smuzhiyun if (output_name != NULL) {
5109*4882a593Smuzhiyun err = trace__open_output(&trace, output_name);
5110*4882a593Smuzhiyun if (err < 0) {
5111*4882a593Smuzhiyun perror("failed to create output file");
5112*4882a593Smuzhiyun goto out;
5113*4882a593Smuzhiyun }
5114*4882a593Smuzhiyun }
5115*4882a593Smuzhiyun
5116*4882a593Smuzhiyun err = evswitch__init(&trace.evswitch, trace.evlist, stderr);
5117*4882a593Smuzhiyun if (err)
5118*4882a593Smuzhiyun goto out_close;
5119*4882a593Smuzhiyun
5120*4882a593Smuzhiyun err = target__validate(&trace.opts.target);
5121*4882a593Smuzhiyun if (err) {
5122*4882a593Smuzhiyun target__strerror(&trace.opts.target, err, bf, sizeof(bf));
5123*4882a593Smuzhiyun fprintf(trace.output, "%s", bf);
5124*4882a593Smuzhiyun goto out_close;
5125*4882a593Smuzhiyun }
5126*4882a593Smuzhiyun
5127*4882a593Smuzhiyun err = target__parse_uid(&trace.opts.target);
5128*4882a593Smuzhiyun if (err) {
5129*4882a593Smuzhiyun target__strerror(&trace.opts.target, err, bf, sizeof(bf));
5130*4882a593Smuzhiyun fprintf(trace.output, "%s", bf);
5131*4882a593Smuzhiyun goto out_close;
5132*4882a593Smuzhiyun }
5133*4882a593Smuzhiyun
5134*4882a593Smuzhiyun if (!argc && target__none(&trace.opts.target))
5135*4882a593Smuzhiyun trace.opts.target.system_wide = true;
5136*4882a593Smuzhiyun
5137*4882a593Smuzhiyun if (input_name)
5138*4882a593Smuzhiyun err = trace__replay(&trace);
5139*4882a593Smuzhiyun else
5140*4882a593Smuzhiyun err = trace__run(&trace, argc, argv);
5141*4882a593Smuzhiyun
5142*4882a593Smuzhiyun out_close:
5143*4882a593Smuzhiyun if (output_name != NULL)
5144*4882a593Smuzhiyun fclose(trace.output);
5145*4882a593Smuzhiyun out:
5146*4882a593Smuzhiyun zfree(&trace.perfconfig_events);
5147*4882a593Smuzhiyun return err;
5148*4882a593Smuzhiyun }
5149