blob: 41799596c04567e430b3cc379714dbd43e992761 [file] [log] [blame]
Arnaldo Carvalho de Meloa598bb52015-08-28 12:02:37 -03001/*
2 * builtin-trace.c
3 *
4 * Builtin 'trace' command:
5 *
6 * Display a continuously updated trace of any workload, CPU, specific PID,
7 * system wide, etc. Default format is loosely strace like, but any other
8 * event may be specified using --event.
9 *
10 * Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
11 *
12 * Initially based on the 'trace' prototype by Thomas Gleixner:
13 *
14 * http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
15 *
16 * Released under the GPL v2. (and only v2, not any later version)
17 */
18
Robert Richter4e319022013-06-11 17:29:18 +020019#include <traceevent/event-parse.h>
Jiri Olsa988bdb32015-09-02 09:56:35 +020020#include <api/fs/tracing_path.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030021#include "builtin.h"
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -030022#include "util/cgroup.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030023#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -030024#include "util/debug.h"
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +010025#include "util/env.h"
Arnaldo Carvalho de Melo5ab8c682017-04-25 15:30:47 -030026#include "util/event.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030027#include "util/evlist.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060028#include <subcmd/exec-cmd.h>
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030029#include "util/machine.h"
Arnaldo Carvalho de Melo9a3993d2017-04-18 11:33:48 -030030#include "util/path.h"
David Ahern6810fc92013-08-28 22:29:52 -060031#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -030032#include "util/thread.h"
Josh Poimboeuf4b6ab942015-12-15 09:39:39 -060033#include <subcmd/parse-options.h>
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030034#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060035#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030036#include "util/thread_map.h"
David Ahernbf2575c2013-10-08 21:26:53 -060037#include "util/stat.h"
Arnaldo Carvalho de Melofd5cead2017-03-14 16:19:30 -030038#include "trace/beauty/beauty.h"
Jiri Olsa97978b32013-12-03 14:09:24 +010039#include "trace-event.h"
David Ahern9aca7f12013-12-04 19:41:39 -070040#include "util/parse-events.h"
Wang Nanba504232016-02-26 09:31:54 +000041#include "util/bpf-loader.h"
Milian Wolff566a0882016-04-08 13:34:15 +020042#include "callchain.h"
Arnaldo Carvalho de Melofea01392017-04-17 16:23:22 -030043#include "print_binary.h"
Arnaldo Carvalho de Meloa0675582017-04-17 16:51:59 -030044#include "string2.h"
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030045#include "syscalltbl.h"
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -030046#include "rb_resort.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030047
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -030048#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -030049#include <inttypes.h>
Arnaldo Carvalho de Melo42087352017-04-19 19:06:30 -030050#include <poll.h>
Arnaldo Carvalho de Melo9607ad32017-04-19 15:49:18 -030051#include <signal.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030052#include <stdlib.h>
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -030053#include <string.h>
Jiri Olsa8dd2a132015-09-07 10:38:06 +020054#include <linux/err.h>
Arnaldo Carvalho de Melo997bba82016-03-30 19:43:32 -030055#include <linux/filter.h>
Arnaldo Carvalho de Melo877a7a12017-04-17 11:39:06 -030056#include <linux/kernel.h>
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -030057#include <linux/random.h>
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -030058#include <linux/stringify.h>
Arnaldo Carvalho de Melobd48c632016-08-05 15:40:30 -030059#include <linux/time64.h>
Arnaldo Carvalho de Melobafae982018-01-22 16:42:16 -030060#include <fcntl.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030061
Arnaldo Carvalho de Melo3d689ed2017-04-17 16:10:49 -030062#include "sane_ctype.h"
63
Arnaldo Carvalho de Meloc188e7a2015-05-14 17:39:03 -030064#ifndef O_CLOEXEC
65# define O_CLOEXEC 02000000
66#endif
67
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -030068#ifndef F_LINUX_SPECIFIC_BASE
69# define F_LINUX_SPECIFIC_BASE 1024
70#endif
71
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030072struct trace {
73 struct perf_tool tool;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -030074 struct syscalltbl *sctbl;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030075 struct {
76 int max;
77 struct syscall *table;
78 struct {
79 struct perf_evsel *sys_enter,
80 *sys_exit;
81 } events;
82 } syscalls;
83 struct record_opts opts;
84 struct perf_evlist *evlist;
85 struct machine *host;
86 struct thread *current;
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -030087 struct cgroup *cgroup;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030088 u64 base_time;
89 FILE *output;
90 unsigned long nr_events;
91 struct strlist *ev_qualifier;
92 struct {
93 size_t nr;
94 int *entries;
95 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030096 struct {
97 size_t nr;
98 pid_t *entries;
99 } filter_pids;
100 double duration_filter;
101 double runtime_ms;
102 struct {
103 u64 vfs_getname,
104 proc_getname;
105 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300106 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300107 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300108 bool not_ev_qualifier;
109 bool live;
110 bool full_time;
111 bool sched;
112 bool multiple_threads;
113 bool summary;
114 bool summary_only;
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -0300115 bool failure_only;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300116 bool show_comm;
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -0300117 bool print_sample;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300118 bool show_tool_stats;
119 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300120 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300121 bool force;
122 bool vfs_getname;
123 int trace_pgfaults;
124};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300125
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300126struct tp_field {
127 int offset;
128 union {
129 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
130 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
131 };
132};
133
134#define TP_UINT_FIELD(bits) \
135static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
136{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500137 u##bits value; \
138 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
139 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300140}
141
142TP_UINT_FIELD(8);
143TP_UINT_FIELD(16);
144TP_UINT_FIELD(32);
145TP_UINT_FIELD(64);
146
147#define TP_UINT_FIELD__SWAPPED(bits) \
148static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
149{ \
David Ahern55d43bc2015-02-19 15:00:22 -0500150 u##bits value; \
151 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300152 return bswap_##bits(value);\
153}
154
155TP_UINT_FIELD__SWAPPED(16);
156TP_UINT_FIELD__SWAPPED(32);
157TP_UINT_FIELD__SWAPPED(64);
158
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300159static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300160{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300161 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300162
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300163 switch (size) {
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300164 case 1:
165 field->integer = tp_field__u8;
166 break;
167 case 2:
168 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
169 break;
170 case 4:
171 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
172 break;
173 case 8:
174 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
175 break;
176 default:
177 return -1;
178 }
179
180 return 0;
181}
182
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300183static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap)
184{
185 return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
186}
187
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300188static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
189{
190 return sample->raw_data + field->offset;
191}
192
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300193static int __tp_field__init_ptr(struct tp_field *field, int offset)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300194{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300195 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300196 field->pointer = tp_field__ptr;
197 return 0;
198}
199
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300200static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
201{
202 return __tp_field__init_ptr(field, format_field->offset);
203}
204
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300205struct syscall_tp {
206 struct tp_field id;
207 union {
208 struct tp_field args, ret;
209 };
210};
211
212static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
213 struct tp_field *field,
214 const char *name)
215{
216 struct format_field *format_field = perf_evsel__field(evsel, name);
217
218 if (format_field == NULL)
219 return -1;
220
221 return tp_field__init_uint(field, format_field, evsel->needs_swap);
222}
223
224#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
225 ({ struct syscall_tp *sc = evsel->priv;\
226 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
227
228static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
229 struct tp_field *field,
230 const char *name)
231{
232 struct format_field *format_field = perf_evsel__field(evsel, name);
233
234 if (format_field == NULL)
235 return -1;
236
237 return tp_field__init_ptr(field, format_field);
238}
239
240#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
241 ({ struct syscall_tp *sc = evsel->priv;\
242 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
243
244static void perf_evsel__delete_priv(struct perf_evsel *evsel)
245{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300246 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300247 perf_evsel__delete(evsel);
248}
249
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -0300250static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel)
251{
252 struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
253
254 if (evsel->priv != NULL) {
255 if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr"))
256 goto out_delete;
257 return 0;
258 }
259
260 return -ENOMEM;
261out_delete:
262 zfree(&evsel->priv);
263 return -ENOENT;
264}
265
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300266static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler)
Namhyung Kim96695d42013-11-12 08:51:45 -0300267{
268 evsel->priv = malloc(sizeof(struct syscall_tp));
269 if (evsel->priv != NULL) {
270 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
271 goto out_delete;
272
273 evsel->handler = handler;
274 return 0;
275 }
276
277 return -ENOMEM;
278
279out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300280 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300281 return -ENOENT;
282}
283
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300284static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300285{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300286 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300287
David Ahern9aca7f12013-12-04 19:41:39 -0700288 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200289 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700290 evsel = perf_evsel__newtp("syscalls", direction);
291
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200292 if (IS_ERR(evsel))
293 return NULL;
294
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300295 if (perf_evsel__init_raw_syscall_tp(evsel, handler))
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200296 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300297
298 return evsel;
299
300out_delete:
301 perf_evsel__delete_priv(evsel);
302 return NULL;
303}
304
305#define perf_evsel__sc_tp_uint(evsel, name, sample) \
306 ({ struct syscall_tp *fields = evsel->priv; \
307 fields->name.integer(&fields->name, sample); })
308
309#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
310 ({ struct syscall_tp *fields = evsel->priv; \
311 fields->name.pointer(&fields->name, sample); })
312
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300313size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
314{
315 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316
Arnaldo Carvalho de Melobc972ad2018-07-26 15:30:33 -0300317 if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL)
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300318 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300319
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300320 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300321}
322
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300323static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
324 const char *intfmt,
325 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300326{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300327 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300328}
329
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300330static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
331 struct syscall_arg *arg)
332{
333 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
334}
335
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300336#define SCA_STRARRAY syscall_arg__scnprintf_strarray
337
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300338struct strarrays {
339 int nr_entries;
340 struct strarray **entries;
341};
342
343#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
344 .nr_entries = ARRAY_SIZE(array), \
345 .entries = array, \
346}
347
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300348size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
349 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300350{
351 struct strarrays *sas = arg->parm;
352 int i;
353
354 for (i = 0; i < sas->nr_entries; ++i) {
355 struct strarray *sa = sas->entries[i];
356 int idx = arg->val - sa->offset;
357
358 if (idx >= 0 && idx < sa->nr_entries) {
359 if (sa->entries[idx] == NULL)
360 break;
361 return scnprintf(bf, size, "%s", sa->entries[idx]);
362 }
363 }
364
365 return scnprintf(bf, size, "%d", arg->val);
366}
367
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300368#ifndef AT_FDCWD
369#define AT_FDCWD -100
370#endif
371
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300372static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
373 struct syscall_arg *arg)
374{
375 int fd = arg->val;
376
377 if (fd == AT_FDCWD)
378 return scnprintf(bf, size, "CWD");
379
380 return syscall_arg__scnprintf_fd(bf, size, arg);
381}
382
383#define SCA_FDAT syscall_arg__scnprintf_fd_at
384
385static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
386 struct syscall_arg *arg);
387
388#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
389
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300390size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300391{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300392 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300393}
394
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300395size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300396{
397 return scnprintf(bf, size, "%d", arg->val);
398}
399
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300400size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
401{
402 return scnprintf(bf, size, "%ld", arg->val);
403}
404
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300405static const char *bpf_cmd[] = {
406 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
407 "MAP_GET_NEXT_KEY", "PROG_LOAD",
408};
409static DEFINE_STRARRAY(bpf_cmd);
410
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300411static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
412static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300413
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300414static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
415static DEFINE_STRARRAY(itimers);
416
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300417static const char *keyctl_options[] = {
418 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
419 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
420 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
421 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
422 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
423};
424static DEFINE_STRARRAY(keyctl_options);
425
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300426static const char *whences[] = { "SET", "CUR", "END",
427#ifdef SEEK_DATA
428"DATA",
429#endif
430#ifdef SEEK_HOLE
431"HOLE",
432#endif
433};
434static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300435
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300436static const char *fcntl_cmds[] = {
437 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300438 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
439 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
440 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300441};
442static DEFINE_STRARRAY(fcntl_cmds);
443
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300444static const char *fcntl_linux_specific_cmds[] = {
445 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
446 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300447 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300448};
449
450static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
451
452static struct strarray *fcntl_cmds_arrays[] = {
453 &strarray__fcntl_cmds,
454 &strarray__fcntl_linux_specific_cmds,
455};
456
457static DEFINE_STRARRAYS(fcntl_cmds_arrays);
458
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300459static const char *rlimit_resources[] = {
460 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
461 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
462 "RTTIME",
463};
464static DEFINE_STRARRAY(rlimit_resources);
465
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300466static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
467static DEFINE_STRARRAY(sighow);
468
David Ahern4f8c1b72013-09-22 19:45:00 -0600469static const char *clockid[] = {
470 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300471 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
472 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600473};
474static DEFINE_STRARRAY(clockid);
475
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300476static const char *socket_families[] = {
477 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
478 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
479 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
480 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
481 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
482 "ALG", "NFC", "VSOCK",
483};
484static DEFINE_STRARRAY(socket_families);
485
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300486static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
487 struct syscall_arg *arg)
488{
489 size_t printed = 0;
490 int mode = arg->val;
491
492 if (mode == F_OK) /* 0 */
493 return scnprintf(bf, size, "F");
494#define P_MODE(n) \
495 if (mode & n##_OK) { \
496 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
497 mode &= ~n##_OK; \
498 }
499
500 P_MODE(R);
501 P_MODE(W);
502 P_MODE(X);
503#undef P_MODE
504
505 if (mode)
506 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
507
508 return printed;
509}
510
511#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
512
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300513static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
514 struct syscall_arg *arg);
515
516#define SCA_FILENAME syscall_arg__scnprintf_filename
517
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300518static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
519 struct syscall_arg *arg)
520{
521 int printed = 0, flags = arg->val;
522
523#define P_FLAG(n) \
524 if (flags & O_##n) { \
525 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
526 flags &= ~O_##n; \
527 }
528
529 P_FLAG(CLOEXEC);
530 P_FLAG(NONBLOCK);
531#undef P_FLAG
532
533 if (flags)
534 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
535
536 return printed;
537}
538
539#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
540
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300541#ifndef GRND_NONBLOCK
542#define GRND_NONBLOCK 0x0001
543#endif
544#ifndef GRND_RANDOM
545#define GRND_RANDOM 0x0002
546#endif
547
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300548static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
549 struct syscall_arg *arg)
550{
551 int printed = 0, flags = arg->val;
552
553#define P_FLAG(n) \
554 if (flags & GRND_##n) { \
555 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
556 flags &= ~GRND_##n; \
557 }
558
559 P_FLAG(RANDOM);
560 P_FLAG(NONBLOCK);
561#undef P_FLAG
562
563 if (flags)
564 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
565
566 return printed;
567}
568
569#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
570
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300571#define STRARRAY(name, array) \
572 { .scnprintf = SCA_STRARRAY, \
573 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300574
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +0100575#include "trace/beauty/arch_errno_names.c"
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300576#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300577#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300578#include "trace/beauty/futex_val3.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300579#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300580#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300581#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300582#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300583#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300584#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300585#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300586#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300587#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300588#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300589#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300590
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300591struct syscall_arg_fmt {
592 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
593 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300594 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300595 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300596};
597
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300598static struct syscall_fmt {
599 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300600 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300601 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300602 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300603 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300604 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300605 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300606} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300607 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300608 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300609 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300610 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300611 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300612 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300613 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300614 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300615 { .name = "clone", .errpid = true, .nr_args = 5,
616 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
617 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
618 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
619 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
620 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300621 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300622 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300623 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300624 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300625 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300626 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300627 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300628 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300629 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300630 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300631 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300632 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300633 .parm = &strarrays__fcntl_cmds_arrays,
634 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300635 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300636 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300638 { .name = "fstat", .alias = "newfstat", },
639 { .name = "fstatat", .alias = "newfstatat", },
640 { .name = "futex",
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300641 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
642 [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300643 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300644 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300645 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300646 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300647 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300648 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300649 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300650 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300651 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300652 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo2d1073d2018-01-09 12:03:47 -0300654 { .name = "gettid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300655 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300656 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300657#if defined(__i386__) || defined(__x86_64__)
658/*
659 * FIXME: Make this available to all arches.
660 */
Arnaldo Carvalho de Melo1cc47f22017-07-31 13:20:14 -0300661 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300662 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300663#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300664 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300665#endif
Arnaldo Carvalho de Melo1de30382017-10-31 11:32:23 -0300666 { .name = "kcmp", .nr_args = 5,
667 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
668 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
669 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
670 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
671 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300672 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300673 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300674 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300675 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300676 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300677 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300678 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300679 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300680 { .name = "lstat", .alias = "newlstat", },
681 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300682 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
683 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300684 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300685 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300686 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300688 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300689 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300690 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300691 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300692 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200693/* The standard mmap maps to old_mmap on s390x */
694#if defined(__s390x__)
695 .alias = "old_mmap",
696#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300697 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
698 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
699 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300700 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300701 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
702 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300705 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300706 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
707 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
708 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300710 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300711 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300717 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300718 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300719 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300720 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
721 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300722 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300723 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
724 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300726 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
727 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
728 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300729 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300730 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300731 { .name = "pkey_alloc",
732 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
733 { .name = "pkey_free",
734 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
735 { .name = "pkey_mprotect",
736 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
737 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
738 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300739 { .name = "poll", .timeout = true, },
740 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300741 { .name = "prctl", .alias = "arch_prctl",
742 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
743 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
744 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300745 { .name = "pread", .alias = "pread64", },
746 { .name = "preadv", .alias = "pread", },
747 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300748 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300749 { .name = "pwrite", .alias = "pwrite64", },
750 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300752 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300753 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300756 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300757 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300758 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300759 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300760 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300761 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300762 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300763 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300764 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300765 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300766 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300767 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300768 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300769 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300770 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300771 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
772 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300773 { .name = "select", .timeout = true, },
774 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300775 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300776 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300777 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300778 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300779 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300780 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300781 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300782 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300783 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300784 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300785 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300786 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300787 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
788 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300789 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300790 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300791 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
792 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300793 { .name = "stat", .alias = "newstat", },
794 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300795 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
796 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
797 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300798 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300799 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300800 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300801 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300802 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300803 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300804 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300805 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300806 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300807 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300808 { .name = "uname", .alias = "newuname", },
809 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300810 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300811 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300812 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300813 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300814 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300815 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300816 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300817};
818
819static int syscall_fmt__cmp(const void *name, const void *fmtp)
820{
821 const struct syscall_fmt *fmt = fmtp;
822 return strcmp(name, fmt->name);
823}
824
825static struct syscall_fmt *syscall_fmt__find(const char *name)
826{
827 const int nmemb = ARRAY_SIZE(syscall_fmts);
828 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
829}
830
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300831/*
832 * is_exit: is this "exit" or "exit_group"?
833 * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
834 */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300835struct syscall {
836 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300837 int nr_args;
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300838 bool is_exit;
839 bool is_open;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300840 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300841 const char *name;
842 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300843 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300844};
845
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300846/*
847 * We need to have this 'calculated' boolean because in some cases we really
848 * don't know what is the duration of a syscall, for instance, when we start
849 * a session and some threads are waiting for a syscall to finish, say 'poll',
850 * in which case all we can do is to print "( ? ) for duration and for the
851 * start timestamp.
852 */
853static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200854{
855 double duration = (double)t / NSEC_PER_MSEC;
856 size_t printed = fprintf(fp, "(");
857
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300858 if (!calculated)
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -0300859 printed += fprintf(fp, " ");
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300860 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200861 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
862 else if (duration >= 0.01)
863 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
864 else
865 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300866 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200867}
868
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300869/**
870 * filename.ptr: The filename char pointer that will be vfs_getname'd
871 * filename.entry_str_pos: Where to insert the string translated from
872 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300873 * ret_scnprintf: syscall args may set this to a different syscall return
874 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300875 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876struct thread_trace {
877 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300878 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300879 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400880 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300881 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300882 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300883 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300884 struct {
885 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300886 short int entry_str_pos;
887 bool pending_open;
888 unsigned int namelen;
889 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300890 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300891 struct {
892 int max;
893 char **table;
894 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600895
896 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897};
898
899static struct thread_trace *thread_trace__new(void)
900{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300901 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
902
903 if (ttrace)
904 ttrace->paths.max = -1;
905
David Ahernbf2575c2013-10-08 21:26:53 -0600906 ttrace->syscall_stats = intlist__new(NULL);
907
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909}
910
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300911static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300913 struct thread_trace *ttrace;
914
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300915 if (thread == NULL)
916 goto fail;
917
Namhyung Kim89dceb22014-10-06 09:46:03 +0900918 if (thread__priv(thread) == NULL)
919 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300920
Namhyung Kim89dceb22014-10-06 09:46:03 +0900921 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300922 goto fail;
923
Namhyung Kim89dceb22014-10-06 09:46:03 +0900924 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300925 ++ttrace->nr_events;
926
927 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300928fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300929 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300930 "WARNING: not enough memory, dropping samples!\n");
931 return NULL;
932}
933
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300934
935void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300936 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300937{
938 struct thread_trace *ttrace = thread__priv(arg->thread);
939
940 ttrace->ret_scnprintf = ret_scnprintf;
941}
942
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400943#define TRACE_PFMAJ (1 << 0)
944#define TRACE_PFMIN (1 << 1)
945
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300946static const size_t trace__entry_str_size = 2048;
947
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300948static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300949{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900950 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300951
952 if (fd > ttrace->paths.max) {
953 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
954
955 if (npath == NULL)
956 return -1;
957
958 if (ttrace->paths.max != -1) {
959 memset(npath + ttrace->paths.max + 1, 0,
960 (fd - ttrace->paths.max) * sizeof(char *));
961 } else {
962 memset(npath, 0, (fd + 1) * sizeof(char *));
963 }
964
965 ttrace->paths.table = npath;
966 ttrace->paths.max = fd;
967 }
968
969 ttrace->paths.table[fd] = strdup(pathname);
970
971 return ttrace->paths.table[fd] != NULL ? 0 : -1;
972}
973
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300974static int thread__read_fd_path(struct thread *thread, int fd)
975{
976 char linkname[PATH_MAX], pathname[PATH_MAX];
977 struct stat st;
978 int ret;
979
980 if (thread->pid_ == thread->tid) {
981 scnprintf(linkname, sizeof(linkname),
982 "/proc/%d/fd/%d", thread->pid_, fd);
983 } else {
984 scnprintf(linkname, sizeof(linkname),
985 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
986 }
987
988 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
989 return -1;
990
991 ret = readlink(linkname, pathname, sizeof(pathname));
992
993 if (ret < 0 || ret > st.st_size)
994 return -1;
995
996 pathname[ret] = '\0';
997 return trace__set_fd_pathname(thread, fd, pathname);
998}
999
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001000static const char *thread__fd_path(struct thread *thread, int fd,
1001 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001002{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001003 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001004
1005 if (ttrace == NULL)
1006 return NULL;
1007
1008 if (fd < 0)
1009 return NULL;
1010
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001011 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001012 if (!trace->live)
1013 return NULL;
1014 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001015 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001016 return NULL;
1017 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001018
1019 return ttrace->paths.table[fd];
1020}
1021
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001022size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001023{
1024 int fd = arg->val;
1025 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001026 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027
1028 if (path)
1029 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1030
1031 return printed;
1032}
1033
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -03001034size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1035{
1036 size_t printed = scnprintf(bf, size, "%d", fd);
1037 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1038
1039 if (thread) {
1040 const char *path = thread__fd_path(thread, fd, trace);
1041
1042 if (path)
1043 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1044
1045 thread__put(thread);
1046 }
1047
1048 return printed;
1049}
1050
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001051static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1052 struct syscall_arg *arg)
1053{
1054 int fd = arg->val;
1055 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001056 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001057
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001058 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1059 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001060
1061 return printed;
1062}
1063
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001064static void thread__set_filename_pos(struct thread *thread, const char *bf,
1065 unsigned long ptr)
1066{
1067 struct thread_trace *ttrace = thread__priv(thread);
1068
1069 ttrace->filename.ptr = ptr;
1070 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1071}
1072
1073static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1074 struct syscall_arg *arg)
1075{
1076 unsigned long ptr = arg->val;
1077
1078 if (!arg->trace->vfs_getname)
1079 return scnprintf(bf, size, "%#x", ptr);
1080
1081 thread__set_filename_pos(arg->thread, bf, ptr);
1082 return 0;
1083}
1084
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001085static bool trace__filter_duration(struct trace *trace, double t)
1086{
1087 return t < (trace->duration_filter * NSEC_PER_MSEC);
1088}
1089
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001090static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001091{
1092 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1093
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001094 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001095}
1096
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001097/*
1098 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1099 * using ttrace->entry_time for a thread that receives a sys_exit without
1100 * first having received a sys_enter ("poll" issued before tracing session
1101 * starts, lost sys_enter exit due to ring buffer overflow).
1102 */
1103static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1104{
1105 if (tstamp > 0)
1106 return __trace__fprintf_tstamp(trace, tstamp, fp);
1107
1108 return fprintf(fp, " ? ");
1109}
1110
Namhyung Kimf15eb532012-10-05 14:02:16 +09001111static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001112static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001113
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001114static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001115{
1116 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001117 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001118}
1119
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001121 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122{
1123 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001124 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001125
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001126 if (trace->multiple_threads) {
1127 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001128 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001129 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001130 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001131
1132 return printed;
1133}
1134
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001135static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001136 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001137{
1138 int ret = 0;
1139
1140 switch (event->header.type) {
1141 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001142 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001143 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001144 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001145 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001146 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001147 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 break;
1149 }
1150
1151 return ret;
1152}
1153
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001154static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001155 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001156 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001157 struct machine *machine)
1158{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001159 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001160 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001161}
1162
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001163static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1164{
1165 struct machine *machine = vmachine;
1166
1167 if (machine->kptr_restrict_warned)
1168 return NULL;
1169
1170 if (symbol_conf.kptr_restrict) {
1171 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1172 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1173 "Kernel samples will not be resolved.\n");
1174 machine->kptr_restrict_warned = true;
1175 return NULL;
1176 }
1177
1178 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1179}
1180
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001181static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1182{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001183 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001184
1185 if (err)
1186 return err;
1187
David Ahern8fb598e2013-09-28 13:13:00 -06001188 trace->host = machine__new_host();
1189 if (trace->host == NULL)
1190 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001191
Andrei Vagincbd5c172017-11-07 16:22:46 -08001192 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1193 if (err < 0)
1194 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001195
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001196 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001197 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001198 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001199out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001200 if (err)
1201 symbol__exit();
1202
1203 return err;
1204}
1205
Andrei Vagin33974a42017-11-07 16:22:45 -08001206static void trace__symbols__exit(struct trace *trace)
1207{
1208 machine__exit(trace->host);
1209 trace->host = NULL;
1210
1211 symbol__exit();
1212}
1213
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001214static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1215{
1216 int idx;
1217
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001218 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1219 nr_args = sc->fmt->nr_args;
1220
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001221 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1222 if (sc->arg_fmt == NULL)
1223 return -1;
1224
1225 for (idx = 0; idx < nr_args; ++idx) {
1226 if (sc->fmt)
1227 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1228 }
1229
1230 sc->nr_args = nr_args;
1231 return 0;
1232}
1233
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001234static int syscall__set_arg_fmts(struct syscall *sc)
1235{
1236 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001237 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001238
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001239 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001240 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1241 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001242
1243 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001244 (strcmp(field->name, "filename") == 0 ||
1245 strcmp(field->name, "path") == 0 ||
1246 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001247 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001248 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001249 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001250 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001251 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001252 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001253 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001254 else if ((strcmp(field->type, "int") == 0 ||
1255 strcmp(field->type, "unsigned int") == 0 ||
1256 strcmp(field->type, "long") == 0) &&
1257 (len = strlen(field->name)) >= 2 &&
1258 strcmp(field->name + len - 2, "fd") == 0) {
1259 /*
1260 * /sys/kernel/tracing/events/syscalls/sys_enter*
1261 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1262 * 65 int
1263 * 23 unsigned int
1264 * 7 unsigned long
1265 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001266 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001267 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001268 }
1269
1270 return 0;
1271}
1272
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001273static int trace__read_syscall_info(struct trace *trace, int id)
1274{
1275 char tp_name[128];
1276 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001277 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001278
1279 if (name == NULL)
1280 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001281
1282 if (id > trace->syscalls.max) {
1283 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1284
1285 if (nsyscalls == NULL)
1286 return -1;
1287
1288 if (trace->syscalls.max != -1) {
1289 memset(nsyscalls + trace->syscalls.max + 1, 0,
1290 (id - trace->syscalls.max) * sizeof(*sc));
1291 } else {
1292 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1293 }
1294
1295 trace->syscalls.table = nsyscalls;
1296 trace->syscalls.max = id;
1297 }
1298
1299 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001300 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001301
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001302 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001303
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001304 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001305 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001306
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001307 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001308 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001309 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001310 }
1311
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001312 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1313 return -1;
1314
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001315 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001316 return -1;
1317
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001318 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001319 /*
1320 * We need to check and discard the first variable '__syscall_nr'
1321 * or 'nr' that mean the syscall number. It is needless here.
1322 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1323 */
1324 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001325 sc->args = sc->args->next;
1326 --sc->nr_args;
1327 }
1328
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001329 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001330 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001331
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001332 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001333}
1334
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001335static int trace__validate_ev_qualifier(struct trace *trace)
1336{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001337 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001338 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001339 struct str_node *pos;
1340
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001341 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1342 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1343 sizeof(trace->ev_qualifier_ids.entries[0]));
1344
1345 if (trace->ev_qualifier_ids.entries == NULL) {
1346 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1347 trace->output);
1348 err = -EINVAL;
1349 goto out;
1350 }
1351
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001352 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001353 i = 0;
1354
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001355 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001356 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001357 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001358
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001359 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001360 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1361 if (id >= 0)
1362 goto matches;
1363
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001364 if (err == 0) {
1365 fputs("Error:\tInvalid syscall ", trace->output);
1366 err = -EINVAL;
1367 } else {
1368 fputs(", ", trace->output);
1369 }
1370
1371 fputs(sc, trace->output);
1372 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001373matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001374 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001375 if (match_next == -1)
1376 continue;
1377
1378 while (1) {
1379 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1380 if (id < 0)
1381 break;
1382 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1383 void *entries;
1384
1385 nr_allocated += 8;
1386 entries = realloc(trace->ev_qualifier_ids.entries,
1387 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1388 if (entries == NULL) {
1389 err = -ENOMEM;
1390 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1391 goto out_free;
1392 }
1393 trace->ev_qualifier_ids.entries = entries;
1394 }
1395 trace->ev_qualifier_ids.nr++;
1396 trace->ev_qualifier_ids.entries[i++] = id;
1397 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001398 }
1399
1400 if (err < 0) {
1401 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1402 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001403out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001404 zfree(&trace->ev_qualifier_ids.entries);
1405 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001406 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001407out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001408 return err;
1409}
1410
David Ahern55d43bc2015-02-19 15:00:22 -05001411/*
1412 * args is to be interpreted as a series of longs but we need to handle
1413 * 8-byte unaligned accesses. args points to raw_data within the event
1414 * and raw_data is guaranteed to be 8-byte unaligned because it is
1415 * preceded by raw_size which is a u32. So we need to copy args to a temp
1416 * variable to read it. Most notably this avoids extended load instructions
1417 * on unaligned addresses
1418 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001419unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001420{
1421 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001422 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001423
1424 memcpy(&val, p, sizeof(val));
1425 return val;
1426}
1427
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001428static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1429 struct syscall_arg *arg)
1430{
1431 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1432 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1433
1434 return scnprintf(bf, size, "arg%d: ", arg->idx);
1435}
1436
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001437static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1438 struct syscall_arg *arg, unsigned long val)
1439{
1440 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1441 arg->val = val;
1442 if (sc->arg_fmt[arg->idx].parm)
1443 arg->parm = sc->arg_fmt[arg->idx].parm;
1444 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1445 }
1446 return scnprintf(bf, size, "%ld", val);
1447}
1448
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001449static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bc2015-02-19 15:00:22 -05001450 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001451 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001452{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001453 size_t printed = 0;
David Ahern55d43bc2015-02-19 15:00:22 -05001454 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001455 u8 bit = 1;
1456 struct syscall_arg arg = {
1457 .args = args,
1458 .idx = 0,
1459 .mask = 0,
1460 .trace = trace,
1461 .thread = thread,
1462 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001463 struct thread_trace *ttrace = thread__priv(thread);
1464
1465 /*
1466 * Things like fcntl will set this in its 'cmd' formatter to pick the
1467 * right formatter for the return value (an fd? file flags?), which is
1468 * not needed for syscalls that always return a given type, say an fd.
1469 */
1470 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001471
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001472 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001473 struct format_field *field;
1474
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001475 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001476 field = field->next, ++arg.idx, bit <<= 1) {
1477 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001478 continue;
David Ahern55d43bc2015-02-19 15:00:22 -05001479
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001480 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bc2015-02-19 15:00:22 -05001481
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001482 /*
1483 * Suppress this argument if its value is zero and
1484 * and we don't have a string associated in an
1485 * strarray for it.
1486 */
David Ahern55d43bc2015-02-19 15:00:22 -05001487 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001488 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001489 (sc->arg_fmt[arg.idx].show_zero ||
1490 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001491 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1492 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001493 continue;
1494
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001495 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001496 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001497 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001498 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001499 } else if (IS_ERR(sc->tp_format)) {
1500 /*
1501 * If we managed to read the tracepoint /format file, then we
1502 * may end up not having any args, like with gettid(), so only
1503 * print the raw args when we didn't manage to read it.
1504 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001505 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001506 if (arg.mask & bit)
1507 goto next_arg;
1508 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001509 if (printed)
1510 printed += scnprintf(bf + printed, size - printed, ", ");
1511 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001512 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1513next_arg:
1514 ++arg.idx;
1515 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001516 }
1517 }
1518
1519 return printed;
1520}
1521
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001522typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001523 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001524 struct perf_sample *sample);
1525
1526static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001527 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001528{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001529
1530 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001531
1532 /*
1533 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1534 * before that, leaving at a higher verbosity level till that is
1535 * explained. Reproduced with plain ftrace with:
1536 *
1537 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1538 * grep "NR -1 " /t/trace_pipe
1539 *
1540 * After generating some load on the machine.
1541 */
1542 if (verbose > 1) {
1543 static u64 n;
1544 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1545 id, perf_evsel__name(evsel), ++n);
1546 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001547 return NULL;
1548 }
1549
1550 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1551 trace__read_syscall_info(trace, id))
1552 goto out_cant_read;
1553
1554 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1555 goto out_cant_read;
1556
1557 return &trace->syscalls.table[id];
1558
1559out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001560 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001561 fprintf(trace->output, "Problems reading syscall %d", id);
1562 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1563 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1564 fputs(" information\n", trace->output);
1565 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001566 return NULL;
1567}
1568
David Ahernbf2575c2013-10-08 21:26:53 -06001569static void thread__update_stats(struct thread_trace *ttrace,
1570 int id, struct perf_sample *sample)
1571{
1572 struct int_node *inode;
1573 struct stats *stats;
1574 u64 duration = 0;
1575
1576 inode = intlist__findnew(ttrace->syscall_stats, id);
1577 if (inode == NULL)
1578 return;
1579
1580 stats = inode->priv;
1581 if (stats == NULL) {
1582 stats = malloc(sizeof(struct stats));
1583 if (stats == NULL)
1584 return;
1585 init_stats(stats);
1586 inode->priv = stats;
1587 }
1588
1589 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1590 duration = sample->time - ttrace->entry_time;
1591
1592 update_stats(stats, duration);
1593}
1594
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001595static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001596{
1597 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001598 size_t printed;
1599
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001600 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001601 return 0;
1602
1603 ttrace = thread__priv(trace->current);
1604
1605 if (!ttrace->entry_pending)
1606 return 0;
1607
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001608 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001609 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1610 ttrace->entry_pending = false;
1611
1612 return printed;
1613}
1614
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001615static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1616 struct perf_sample *sample, struct thread *thread)
1617{
1618 int printed = 0;
1619
1620 if (trace->print_sample) {
1621 double ts = (double)sample->time / NSEC_PER_MSEC;
1622
1623 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1624 perf_evsel__name(evsel), ts,
1625 thread__comm_str(thread),
1626 sample->pid, sample->tid, sample->cpu);
1627 }
1628
1629 return printed;
1630}
1631
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001632static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001633 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001634 struct perf_sample *sample)
1635{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001636 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001637 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001638 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001639 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001640 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001641 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001642 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001643
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001644 if (sc == NULL)
1645 return -1;
1646
David Ahern8fb598e2013-09-28 13:13:00 -06001647 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001648 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001649 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001650 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001651
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001652 trace__fprintf_sample(trace, evsel, sample, thread);
1653
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001654 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001655
1656 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001657 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001658 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001659 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001660 }
1661
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001662 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001663 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001664
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001665 ttrace->entry_time = sample->time;
1666 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001667 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001668
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001669 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001670 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001671
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001672 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001673 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001674 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001675 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001676 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001677 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001679 /* See trace__vfs_getname & trace__sys_exit */
1680 ttrace->filename.pending_open = false;
1681 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001682
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001683 if (trace->current != thread) {
1684 thread__put(trace->current);
1685 trace->current = thread__get(thread);
1686 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001687 err = 0;
1688out_put:
1689 thread__put(thread);
1690 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001691}
1692
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001693static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1694 struct perf_sample *sample)
1695{
1696 struct format_field *field = perf_evsel__field(evsel, "__syscall_nr");
1697 struct thread_trace *ttrace;
1698 struct thread *thread;
1699 struct syscall *sc;
1700 char msg[1024];
1701 int id, err = -1;
1702 void *args;
1703
1704 if (field == NULL)
1705 return -1;
1706
1707 id = format_field__intval(field, sample, evsel->needs_swap);
1708 sc = trace__syscall_info(trace, evsel, id);
1709
1710 if (sc == NULL)
1711 return -1;
1712
1713 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1714 ttrace = thread__trace(thread, trace->output);
1715 /*
1716 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1717 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1718 */
1719 if (ttrace == NULL)
1720 goto out_put;
1721
1722 args = sample->raw_data + field->offset + sizeof(u64); /* skip __syscall_nr, there is where args are */
1723 syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread);
1724 fprintf(trace->output, "%s", msg);
1725 err = 0;
1726out_put:
1727 thread__put(thread);
1728 return err;
1729}
1730
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001731static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1732 struct perf_sample *sample,
1733 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001734{
1735 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301736 int max_stack = evsel->attr.sample_max_stack ?
1737 evsel->attr.sample_max_stack :
1738 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001739
1740 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301741 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001742 return -1;
1743
1744 return 0;
1745}
1746
1747static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1748{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001749 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001750 const unsigned int print_opts = EVSEL__PRINT_SYM |
1751 EVSEL__PRINT_DSO |
1752 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001753
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001754 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001755}
1756
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001757static const char *errno_to_name(struct perf_evsel *evsel, int err)
1758{
1759 struct perf_env *env = perf_evsel__env(evsel);
1760 const char *arch_name = perf_env__arch(env);
1761
1762 return arch_syscalls__strerrno(arch_name, err);
1763}
1764
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001765static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001766 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001767 struct perf_sample *sample)
1768{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001769 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001770 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001771 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001772 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001773 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001774 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001775 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001776
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001777 if (sc == NULL)
1778 return -1;
1779
David Ahern8fb598e2013-09-28 13:13:00 -06001780 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001781 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001782 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001783 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001784
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001785 trace__fprintf_sample(trace, evsel, sample, thread);
1786
David Ahernbf2575c2013-10-08 21:26:53 -06001787 if (trace->summary)
1788 thread__update_stats(ttrace, id, sample);
1789
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001790 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001791
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001792 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001793 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1794 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001795 ++trace->stats.vfs_getname;
1796 }
1797
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001798 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001799 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001800 if (trace__filter_duration(trace, duration))
1801 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001802 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001803 } else if (trace->duration_filter)
1804 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001805
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001806 if (sample->callchain) {
1807 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1808 if (callchain_ret == 0) {
1809 if (callchain_cursor.nr < trace->min_stack)
1810 goto out;
1811 callchain_ret = 1;
1812 }
1813 }
1814
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001815 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001816 goto out;
1817
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001818 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001819
1820 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001821 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001822 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001823 fprintf(trace->output, " ... [");
1824 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1825 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001826 }
1827
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001828 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001829 if (ret < 0)
1830 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001831signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001832 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001833 } else if (ret < 0) {
1834errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001835 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001836 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001837 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001838
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001839 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001840 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001841 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001842 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001843 else if (ttrace->ret_scnprintf) {
1844 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001845 struct syscall_arg arg = {
1846 .val = ret,
1847 .thread = thread,
1848 .trace = trace,
1849 };
1850 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001851 ttrace->ret_scnprintf = NULL;
1852 fprintf(trace->output, ") = %s", bf);
1853 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001854 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001855 else if (sc->fmt->errpid) {
1856 struct thread *child = machine__find_thread(trace->host, ret, ret);
1857
1858 if (child != NULL) {
1859 fprintf(trace->output, ") = %ld", ret);
1860 if (child->comm_set)
1861 fprintf(trace->output, " (%s)", thread__comm_str(child));
1862 thread__put(child);
1863 }
1864 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001865 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001866
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001867 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001868
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001869 if (callchain_ret > 0)
1870 trace__fprintf_callchain(trace, sample);
1871 else if (callchain_ret < 0)
1872 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001873out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001874 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001875 err = 0;
1876out_put:
1877 thread__put(thread);
1878 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001879}
1880
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001881static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001882 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001883 struct perf_sample *sample)
1884{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001885 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1886 struct thread_trace *ttrace;
1887 size_t filename_len, entry_str_len, to_move;
1888 ssize_t remaining_space;
1889 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001890 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001891
1892 if (!thread)
1893 goto out;
1894
1895 ttrace = thread__priv(thread);
1896 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001897 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001898
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001899 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001900 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001901 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001902
1903 if (ttrace->filename.namelen < filename_len) {
1904 char *f = realloc(ttrace->filename.name, filename_len + 1);
1905
1906 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001907 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001908
1909 ttrace->filename.namelen = filename_len;
1910 ttrace->filename.name = f;
1911 }
1912
1913 strcpy(ttrace->filename.name, filename);
1914 ttrace->filename.pending_open = true;
1915
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001916 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001917 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001918
1919 entry_str_len = strlen(ttrace->entry_str);
1920 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1921 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001922 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001923
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001924 if (filename_len > (size_t)remaining_space) {
1925 filename += filename_len - remaining_space;
1926 filename_len = remaining_space;
1927 }
1928
1929 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1930 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1931 memmove(pos + filename_len, pos, to_move);
1932 memcpy(pos, filename, filename_len);
1933
1934 ttrace->filename.ptr = 0;
1935 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001936out_put:
1937 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001938out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001939 return 0;
1940}
1941
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001942static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001943 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001944 struct perf_sample *sample)
1945{
1946 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1947 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001948 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001949 sample->pid,
1950 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001951 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001952
1953 if (ttrace == NULL)
1954 goto out_dump;
1955
1956 ttrace->runtime_ms += runtime_ms;
1957 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001958out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001959 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001960 return 0;
1961
1962out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001963 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001964 evsel->name,
1965 perf_evsel__strval(evsel, sample, "comm"),
1966 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1967 runtime,
1968 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001969 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001970}
1971
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001972static int bpf_output__printer(enum binary_printer_ops op,
1973 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001974{
Wang Nan1d6c9402016-02-26 09:31:55 +00001975 unsigned char ch = (unsigned char)val;
1976
1977 switch (op) {
1978 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001979 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001980 case BINARY_PRINT_DATA_BEGIN:
1981 case BINARY_PRINT_LINE_BEGIN:
1982 case BINARY_PRINT_ADDR:
1983 case BINARY_PRINT_NUM_DATA:
1984 case BINARY_PRINT_NUM_PAD:
1985 case BINARY_PRINT_SEP:
1986 case BINARY_PRINT_CHAR_PAD:
1987 case BINARY_PRINT_LINE_END:
1988 case BINARY_PRINT_DATA_END:
1989 default:
1990 break;
1991 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001992
1993 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00001994}
1995
1996static void bpf_output__fprintf(struct trace *trace,
1997 struct perf_sample *sample)
1998{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001999 binary__fprintf(sample->raw_data, sample->raw_size, 8,
2000 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00002001}
2002
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002003static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2004 union perf_event *event __maybe_unused,
2005 struct perf_sample *sample)
2006{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002007 int callchain_ret = 0;
2008
2009 if (sample->callchain) {
2010 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2011 if (callchain_ret == 0) {
2012 if (callchain_cursor.nr < trace->min_stack)
2013 goto out;
2014 callchain_ret = 1;
2015 }
2016 }
2017
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03002018 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002019 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002020
2021 if (trace->trace_syscalls)
2022 fprintf(trace->output, "( ): ");
2023
2024 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002025
Wang Nan1d6c9402016-02-26 09:31:55 +00002026 if (perf_evsel__is_bpf_output(evsel)) {
2027 bpf_output__fprintf(trace, sample);
2028 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002029 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2030 trace__fprintf_sys_enter(trace, evsel, sample)) {
2031 event_format__fprintf(evsel->tp_format, sample->cpu,
2032 sample->raw_data, sample->raw_size,
2033 trace->output);
2034 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002035 }
2036
Changbin Du51125a22018-03-13 18:40:01 +08002037 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002038
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002039 if (callchain_ret > 0)
2040 trace__fprintf_callchain(trace, sample);
2041 else if (callchain_ret < 0)
2042 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2043out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002044 return 0;
2045}
2046
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002047static void print_location(FILE *f, struct perf_sample *sample,
2048 struct addr_location *al,
2049 bool print_dso, bool print_sym)
2050{
2051
Namhyung Kimbb963e12017-02-17 17:17:38 +09002052 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002053 fprintf(f, "%s@", al->map->dso->long_name);
2054
Namhyung Kimbb963e12017-02-17 17:17:38 +09002055 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002056 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002057 al->addr - al->sym->start);
2058 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002059 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002060 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002061 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002062}
2063
2064static int trace__pgfault(struct trace *trace,
2065 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002066 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002067 struct perf_sample *sample)
2068{
2069 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002070 struct addr_location al;
2071 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002072 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002073 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002074 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002075
2076 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002077
2078 if (sample->callchain) {
2079 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2080 if (callchain_ret == 0) {
2081 if (callchain_cursor.nr < trace->min_stack)
2082 goto out_put;
2083 callchain_ret = 1;
2084 }
2085 }
2086
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002087 ttrace = thread__trace(thread, trace->output);
2088 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002089 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002090
2091 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2092 ttrace->pfmaj++;
2093 else
2094 ttrace->pfmin++;
2095
2096 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002097 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002098
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002099 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002100
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002101 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002102
2103 fprintf(trace->output, "%sfault [",
2104 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2105 "maj" : "min");
2106
2107 print_location(trace->output, sample, &al, false, true);
2108
2109 fprintf(trace->output, "] => ");
2110
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002111 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002112
2113 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002114 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002115
2116 if (al.map)
2117 map_type = 'x';
2118 else
2119 map_type = '?';
2120 }
2121
2122 print_location(trace->output, sample, &al, true, false);
2123
2124 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002125
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002126 if (callchain_ret > 0)
2127 trace__fprintf_callchain(trace, sample);
2128 else if (callchain_ret < 0)
2129 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002130out:
2131 err = 0;
2132out_put:
2133 thread__put(thread);
2134 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002135}
2136
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002137static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002138 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002139 struct perf_sample *sample)
2140{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002141 /*
2142 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2143 * and don't use sample->time unconditionally, we may end up having
2144 * some other event in the future without PERF_SAMPLE_TIME for good
2145 * reason, i.e. we may not be interested in its timestamps, just in
2146 * it taking place, picking some piece of information when it
2147 * appears in our event stream (vfs_getname comes to mind).
2148 */
2149 if (trace->base_time == 0 && !trace->full_time &&
2150 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002151 trace->base_time = sample->time;
2152}
2153
David Ahern6810fc92013-08-28 22:29:52 -06002154static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002155 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002156 struct perf_sample *sample,
2157 struct perf_evsel *evsel,
2158 struct machine *machine __maybe_unused)
2159{
2160 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002161 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002162 int err = 0;
2163
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002164 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002165
David Ahernaa07df62016-11-25 09:29:52 -07002166 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2167 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002168 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002169
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002170 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002171
David Ahern31605652013-12-04 19:41:41 -07002172 if (handler) {
2173 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002174 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002175 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002176out:
2177 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002178 return err;
2179}
2180
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002181static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002182{
2183 unsigned int rec_argc, i, j;
2184 const char **rec_argv;
2185 const char * const record_args[] = {
2186 "record",
2187 "-R",
2188 "-m", "1024",
2189 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002190 };
2191
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002192 const char * const sc_args[] = { "-e", };
2193 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2194 const char * const majpf_args[] = { "-e", "major-faults" };
2195 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2196 const char * const minpf_args[] = { "-e", "minor-faults" };
2197 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2198
David Ahern9aca7f12013-12-04 19:41:39 -07002199 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002200 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2201 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002202 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2203
2204 if (rec_argv == NULL)
2205 return -ENOMEM;
2206
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002207 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002208 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002209 rec_argv[j++] = record_args[i];
2210
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002211 if (trace->trace_syscalls) {
2212 for (i = 0; i < sc_args_nr; i++)
2213 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002214
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002215 /* event string may be different for older kernels - e.g., RHEL6 */
2216 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2217 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2218 else if (is_valid_tracepoint("syscalls:sys_enter"))
2219 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2220 else {
2221 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002222 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002223 return -1;
2224 }
David Ahern9aca7f12013-12-04 19:41:39 -07002225 }
David Ahern9aca7f12013-12-04 19:41:39 -07002226
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002227 if (trace->trace_pgfaults & TRACE_PFMAJ)
2228 for (i = 0; i < majpf_args_nr; i++)
2229 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002230
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002231 if (trace->trace_pgfaults & TRACE_PFMIN)
2232 for (i = 0; i < minpf_args_nr; i++)
2233 rec_argv[j++] = minpf_args[i];
2234
2235 for (i = 0; i < (unsigned int)argc; i++)
2236 rec_argv[j++] = argv[i];
2237
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002238 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002239}
2240
David Ahernbf2575c2013-10-08 21:26:53 -06002241static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2242
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002243static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002244{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002245 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002246
2247 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002248 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002249
2250 if (perf_evsel__field(evsel, "pathname") == NULL) {
2251 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002252 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002253 }
2254
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002255 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002256 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002257 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002258}
2259
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002260static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002261{
2262 struct perf_evsel *evsel;
2263 struct perf_event_attr attr = {
2264 .type = PERF_TYPE_SOFTWARE,
2265 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002266 };
2267
2268 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002269 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002270
2271 event_attr_init(&attr);
2272
2273 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002274 if (evsel)
2275 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002276
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002277 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002278}
2279
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002280static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2281{
2282 const u32 type = event->header.type;
2283 struct perf_evsel *evsel;
2284
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002285 if (type != PERF_RECORD_SAMPLE) {
2286 trace__process_event(trace, trace->host, event, sample);
2287 return;
2288 }
2289
2290 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2291 if (evsel == NULL) {
2292 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2293 return;
2294 }
2295
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002296 trace__set_base_time(trace, evsel, sample);
2297
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002298 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2299 sample->raw_data == NULL) {
2300 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2301 perf_evsel__name(evsel), sample->tid,
2302 sample->cpu, sample->raw_size);
2303 } else {
2304 tracepoint_handler handler = evsel->handler;
2305 handler(trace, evsel, event, sample);
2306 }
2307}
2308
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002309static int trace__add_syscall_newtp(struct trace *trace)
2310{
2311 int ret = -1;
2312 struct perf_evlist *evlist = trace->evlist;
2313 struct perf_evsel *sys_enter, *sys_exit;
2314
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002315 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002316 if (sys_enter == NULL)
2317 goto out;
2318
2319 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2320 goto out_delete_sys_enter;
2321
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002322 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002323 if (sys_exit == NULL)
2324 goto out_delete_sys_enter;
2325
2326 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2327 goto out_delete_sys_exit;
2328
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002329 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2330 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2331
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002332 perf_evlist__add(evlist, sys_enter);
2333 perf_evlist__add(evlist, sys_exit);
2334
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002335 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002336 /*
2337 * We're interested only in the user space callchain
2338 * leading to the syscall, allow overriding that for
2339 * debugging reasons using --kernel_syscall_callchains
2340 */
2341 sys_exit->attr.exclude_callchain_kernel = 1;
2342 }
2343
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002344 trace->syscalls.events.sys_enter = sys_enter;
2345 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002346
2347 ret = 0;
2348out:
2349 return ret;
2350
2351out_delete_sys_exit:
2352 perf_evsel__delete_priv(sys_exit);
2353out_delete_sys_enter:
2354 perf_evsel__delete_priv(sys_enter);
2355 goto out;
2356}
2357
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002358static int trace__set_ev_qualifier_filter(struct trace *trace)
2359{
2360 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002361 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002362 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2363 trace->ev_qualifier_ids.nr,
2364 trace->ev_qualifier_ids.entries);
2365
2366 if (filter == NULL)
2367 goto out_enomem;
2368
Mathieu Poirier3541c032016-09-16 08:44:04 -06002369 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2370 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002371 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002372 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002373 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002374
2375 free(filter);
2376out:
2377 return err;
2378out_enomem:
2379 errno = ENOMEM;
2380 goto out;
2381}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002382
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002383static int trace__set_filter_loop_pids(struct trace *trace)
2384{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002385 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002386 pid_t pids[32] = {
2387 getpid(),
2388 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002389 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2390
2391 while (thread && nr < ARRAY_SIZE(pids)) {
2392 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2393
2394 if (parent == NULL)
2395 break;
2396
2397 if (!strcmp(thread__comm_str(parent), "sshd")) {
2398 pids[nr++] = parent->tid;
2399 break;
2400 }
2401 thread = parent;
2402 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002403
2404 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2405}
2406
Namhyung Kimf15eb532012-10-05 14:02:16 +09002407static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002408{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002409 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002410 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002411 int err = -1, i;
2412 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002413 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002414 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002415
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002416 trace->live = true;
2417
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002418 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002419 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002420
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002421 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002422 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002423
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002424 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2425 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2426 if (pgfault_maj == NULL)
2427 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002428 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002429 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002430 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002431
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002432 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2433 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2434 if (pgfault_min == NULL)
2435 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002436 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002437 perf_evlist__add(evlist, pgfault_min);
2438 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002439
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002440 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002441 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2442 trace__sched_stat_runtime))
2443 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002444
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002445 /*
2446 * If a global cgroup was set, apply it to all the events without an
2447 * explicit cgroup. I.e.:
2448 *
2449 * trace -G A -e sched:*switch
2450 *
2451 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2452 * _and_ sched:sched_switch to the 'A' cgroup, while:
2453 *
2454 * trace -e sched:*switch -G A
2455 *
2456 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2457 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2458 * a cgroup (on the root cgroup, sys wide, etc).
2459 *
2460 * Multiple cgroups:
2461 *
2462 * trace -G A -e sched:*switch -G B
2463 *
2464 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2465 * to the 'B' cgroup.
2466 *
2467 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2468 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2469 */
2470 if (trace->cgroup)
2471 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2472
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002473 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2474 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002475 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002476 goto out_delete_evlist;
2477 }
2478
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002479 err = trace__symbols_init(trace, evlist);
2480 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002481 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002482 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002483 }
2484
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002485 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002486
Namhyung Kimf15eb532012-10-05 14:02:16 +09002487 signal(SIGCHLD, sig_handler);
2488 signal(SIGINT, sig_handler);
2489
2490 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002491 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002492 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002493 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002494 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002495 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002496 }
2497 }
2498
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002499 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002500 if (err < 0)
2501 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002502
Wang Nanba504232016-02-26 09:31:54 +00002503 err = bpf__apply_obj_config();
2504 if (err) {
2505 char errbuf[BUFSIZ];
2506
2507 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2508 pr_err("ERROR: Apply config to BPF failed: %s\n",
2509 errbuf);
2510 goto out_error_open;
2511 }
2512
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002513 /*
2514 * Better not use !target__has_task() here because we need to cover the
2515 * case where no threads were specified in the command line, but a
2516 * workload was, and in that case we will fill in the thread_map when
2517 * we fork the workload in perf_evlist__prepare_workload.
2518 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002519 if (trace->filter_pids.nr > 0)
2520 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002521 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002522 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002523
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002524 if (err < 0)
2525 goto out_error_mem;
2526
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002527 if (trace->ev_qualifier_ids.nr > 0) {
2528 err = trace__set_ev_qualifier_filter(trace);
2529 if (err < 0)
2530 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002531
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002532 pr_debug("event qualifier tracepoint filter: %s\n",
2533 trace->syscalls.events.sys_exit->filter);
2534 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002535
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002536 err = perf_evlist__apply_filters(evlist, &evsel);
2537 if (err < 0)
2538 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002539
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002540 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002541 if (err < 0)
2542 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002543
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002544 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002545 perf_evlist__enable(evlist);
2546
Namhyung Kimf15eb532012-10-05 14:02:16 +09002547 if (forks)
2548 perf_evlist__start_workload(evlist);
2549
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002550 if (trace->opts.initial_delay) {
2551 usleep(trace->opts.initial_delay * 1000);
2552 perf_evlist__enable(evlist);
2553 }
2554
Jiri Olsae13798c2015-06-23 00:36:02 +02002555 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002556 evlist->threads->nr > 1 ||
2557 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002558
2559 /*
2560 * Now that we already used evsel->attr to ask the kernel to setup the
2561 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2562 * trace__resolve_callchain(), allowing per-event max-stack settings
2563 * to override an explicitely set --max-stack global setting.
2564 */
2565 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002566 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002567 evsel->attr.sample_max_stack == 0)
2568 evsel->attr.sample_max_stack = trace->max_stack;
2569 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002570again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002571 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002572
2573 for (i = 0; i < evlist->nr_mmaps; i++) {
2574 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002575 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002576
Kan Liangd7f55c62018-03-01 18:08:59 -05002577 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002578 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002579 continue;
2580
Kan Liang0019dc872018-03-06 10:36:06 -05002581 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002582 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002583
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002584 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002585
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002586 err = perf_evlist__parse_sample(evlist, event, &sample);
2587 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002588 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002589 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002590 }
2591
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002592 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002593next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002594 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002595
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002596 if (interrupted)
2597 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002598
2599 if (done && !draining) {
2600 perf_evlist__disable(evlist);
2601 draining = true;
2602 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002603 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002604 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002605 }
2606
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002607 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002608 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002609
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002610 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2611 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2612 draining = true;
2613
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002614 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002615 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002616 } else {
2617 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002618 }
2619
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002620out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002621 thread__zput(trace->current);
2622
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002623 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002624
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002625 if (!err) {
2626 if (trace->summary)
2627 trace__fprintf_thread_summary(trace, trace->output);
2628
2629 if (trace->show_tool_stats) {
2630 fprintf(trace->output, "Stats:\n "
2631 " vfs_getname : %" PRIu64 "\n"
2632 " proc_getname: %" PRIu64 "\n",
2633 trace->stats.vfs_getname,
2634 trace->stats.proc_getname);
2635 }
2636 }
David Ahernbf2575c2013-10-08 21:26:53 -06002637
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002638out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002639 trace__symbols__exit(trace);
2640
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002641 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002642 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002643 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002644 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002645 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002646{
2647 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002648
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002649out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002650 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002651 goto out_error;
2652
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002653out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002654 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002655 goto out_error;
2656
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002657out_error_mmap:
2658 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2659 goto out_error;
2660
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002661out_error_open:
2662 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2663
2664out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002665 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302666 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002667
2668out_error_apply_filters:
2669 fprintf(trace->output,
2670 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2671 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002672 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002673 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002674}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002675out_error_mem:
2676 fprintf(trace->output, "Not enough memory to run!\n");
2677 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002678
2679out_errno:
2680 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2681 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002682}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002683
David Ahern6810fc92013-08-28 22:29:52 -06002684static int trace__replay(struct trace *trace)
2685{
2686 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002687 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002688 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002689 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002690 .file = {
2691 .path = input_name,
2692 },
2693 .mode = PERF_DATA_MODE_READ,
2694 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002695 };
David Ahern6810fc92013-08-28 22:29:52 -06002696 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002697 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002698 int err = -1;
2699
2700 trace->tool.sample = trace__process_sample;
2701 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002702 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002703 trace->tool.comm = perf_event__process_comm;
2704 trace->tool.exit = perf_event__process_exit;
2705 trace->tool.fork = perf_event__process_fork;
2706 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302707 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002708 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302709 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002710
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002711 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002712 trace->tool.ordering_requires_timestamps = true;
2713
2714 /* add tid to output */
2715 trace->multiple_threads = true;
2716
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002717 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002718 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002719 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002720
David Ahernaa07df62016-11-25 09:29:52 -07002721 if (trace->opts.target.pid)
2722 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2723
2724 if (trace->opts.target.tid)
2725 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2726
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002727 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002728 goto out;
2729
David Ahern8fb598e2013-09-28 13:13:00 -06002730 trace->host = &session->machines.host;
2731
David Ahern6810fc92013-08-28 22:29:52 -06002732 err = perf_session__set_tracepoints_handlers(session, handlers);
2733 if (err)
2734 goto out;
2735
Namhyung Kim003824e2013-11-12 15:25:00 +09002736 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2737 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002738 /* older kernels have syscalls tp versus raw_syscalls */
2739 if (evsel == NULL)
2740 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2741 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002742
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002743 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002744 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002745 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002746 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2747 goto out;
2748 }
2749
2750 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2751 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002752 if (evsel == NULL)
2753 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2754 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002755 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002756 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002757 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002758 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002759 goto out;
2760 }
2761
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002762 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002763 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2764 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2765 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2766 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2767 evsel->handler = trace__pgfault;
2768 }
2769
David Ahern6810fc92013-08-28 22:29:52 -06002770 setup_pager();
2771
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002772 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002773 if (err)
2774 pr_err("Failed to process events, error %d", err);
2775
David Ahernbf2575c2013-10-08 21:26:53 -06002776 else if (trace->summary)
2777 trace__fprintf_thread_summary(trace, trace->output);
2778
David Ahern6810fc92013-08-28 22:29:52 -06002779out:
2780 perf_session__delete(session);
2781
2782 return err;
2783}
2784
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002785static size_t trace__fprintf_threads_header(FILE *fp)
2786{
2787 size_t printed;
2788
Pekka Enberg99ff7152013-11-12 16:42:14 +02002789 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002790
2791 return printed;
2792}
2793
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002794DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2795 struct stats *stats;
2796 double msecs;
2797 int syscall;
2798)
2799{
2800 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2801 struct stats *stats = source->priv;
2802
2803 entry->syscall = source->i;
2804 entry->stats = stats;
2805 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2806}
2807
David Ahernbf2575c2013-10-08 21:26:53 -06002808static size_t thread__dump_stats(struct thread_trace *ttrace,
2809 struct trace *trace, FILE *fp)
2810{
David Ahernbf2575c2013-10-08 21:26:53 -06002811 size_t printed = 0;
2812 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002813 struct rb_node *nd;
2814 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002815
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002816 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002817 return 0;
2818
2819 printed += fprintf(fp, "\n");
2820
Milian Wolff834fd462015-08-06 11:24:29 +02002821 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2822 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2823 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002824
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002825 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002826 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002827 if (stats) {
2828 double min = (double)(stats->min) / NSEC_PER_MSEC;
2829 double max = (double)(stats->max) / NSEC_PER_MSEC;
2830 double avg = avg_stats(stats);
2831 double pct;
2832 u64 n = (u64) stats->n;
2833
2834 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2835 avg /= NSEC_PER_MSEC;
2836
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002837 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002838 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002839 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002840 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002841 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002842 }
David Ahernbf2575c2013-10-08 21:26:53 -06002843 }
2844
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002845 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002846 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002847
2848 return printed;
2849}
2850
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002851static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002852{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002853 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002854 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002855 double ratio;
2856
2857 if (ttrace == NULL)
2858 return 0;
2859
2860 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2861
Pekka Enberg15e65c62013-11-14 18:43:30 +02002862 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002863 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002864 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002865 if (ttrace->pfmaj)
2866 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2867 if (ttrace->pfmin)
2868 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002869 if (trace->sched)
2870 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2871 else if (fputc('\n', fp) != EOF)
2872 ++printed;
2873
David Ahernbf2575c2013-10-08 21:26:53 -06002874 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002875
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002876 return printed;
2877}
David Ahern896cbb52013-09-28 13:12:59 -06002878
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002879static unsigned long thread__nr_events(struct thread_trace *ttrace)
2880{
2881 return ttrace ? ttrace->nr_events : 0;
2882}
2883
2884DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2885 struct thread *thread;
2886)
2887{
2888 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002889}
2890
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002891static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2892{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002893 size_t printed = trace__fprintf_threads_header(fp);
2894 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002895 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002896
Kan Liang91e467b2017-09-10 19:23:14 -07002897 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2898 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2899
2900 if (threads == NULL) {
2901 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2902 return 0;
2903 }
2904
2905 resort_rb__for_each_entry(nd, threads)
2906 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2907
2908 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002909 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002910 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002911}
2912
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002913static int trace__set_duration(const struct option *opt, const char *str,
2914 int unset __maybe_unused)
2915{
2916 struct trace *trace = opt->value;
2917
2918 trace->duration_filter = atof(str);
2919 return 0;
2920}
2921
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002922static int trace__set_filter_pids(const struct option *opt, const char *str,
2923 int unset __maybe_unused)
2924{
2925 int ret = -1;
2926 size_t i;
2927 struct trace *trace = opt->value;
2928 /*
2929 * FIXME: introduce a intarray class, plain parse csv and create a
2930 * { int nr, int entries[] } struct...
2931 */
2932 struct intlist *list = intlist__new(str);
2933
2934 if (list == NULL)
2935 return -1;
2936
2937 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2938 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2939
2940 if (trace->filter_pids.entries == NULL)
2941 goto out;
2942
2943 trace->filter_pids.entries[0] = getpid();
2944
2945 for (i = 1; i < trace->filter_pids.nr; ++i)
2946 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2947
2948 intlist__delete(list);
2949 ret = 0;
2950out:
2951 return ret;
2952}
2953
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002954static int trace__open_output(struct trace *trace, const char *filename)
2955{
2956 struct stat st;
2957
2958 if (!stat(filename, &st) && st.st_size) {
2959 char oldname[PATH_MAX];
2960
2961 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2962 unlink(oldname);
2963 rename(filename, oldname);
2964 }
2965
2966 trace->output = fopen(filename, "w");
2967
2968 return trace->output == NULL ? -errno : 0;
2969}
2970
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002971static int parse_pagefaults(const struct option *opt, const char *str,
2972 int unset __maybe_unused)
2973{
2974 int *trace_pgfaults = opt->value;
2975
2976 if (strcmp(str, "all") == 0)
2977 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2978 else if (strcmp(str, "maj") == 0)
2979 *trace_pgfaults |= TRACE_PFMAJ;
2980 else if (strcmp(str, "min") == 0)
2981 *trace_pgfaults |= TRACE_PFMIN;
2982 else
2983 return -1;
2984
2985 return 0;
2986}
2987
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002988static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2989{
2990 struct perf_evsel *evsel;
2991
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002992 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002993 evsel->handler = handler;
2994}
2995
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03002996static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist)
2997{
2998 struct perf_evsel *evsel;
2999
3000 evlist__for_each_entry(evlist, evsel) {
3001 if (evsel->priv || !evsel->tp_format)
3002 continue;
3003
3004 if (strcmp(evsel->tp_format->system, "syscalls"))
3005 continue;
3006
3007 if (perf_evsel__init_syscall_tp(evsel))
3008 return -1;
3009
3010 if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
3011 struct syscall_tp *sc = evsel->priv;
3012
3013 if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
3014 return -1;
3015 } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
3016 struct syscall_tp *sc = evsel->priv;
3017
3018 if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
3019 return -1;
3020 }
3021 }
3022
3023 return 0;
3024}
3025
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003026/*
3027 * XXX: Hackish, just splitting the combined -e+--event (syscalls
3028 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
3029 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
3030 *
3031 * It'd be better to introduce a parse_options() variant that would return a
3032 * list with the terms it didn't match to an event...
3033 */
3034static int trace__parse_events_option(const struct option *opt, const char *str,
3035 int unset __maybe_unused)
3036{
3037 struct trace *trace = (struct trace *)opt->value;
3038 const char *s = str;
3039 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003040 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003041 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
3042 char group_name[PATH_MAX];
3043
3044 if (strace_groups_dir == NULL)
3045 return -1;
3046
3047 if (*s == '!') {
3048 ++s;
3049 trace->not_ev_qualifier = true;
3050 }
3051
3052 while (1) {
3053 if ((sep = strchr(s, ',')) != NULL)
3054 *sep = '\0';
3055
3056 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003057 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3058 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003059 list = 1;
3060 } else {
3061 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3062 if (access(group_name, R_OK) == 0)
3063 list = 1;
3064 }
3065
3066 if (lists[list]) {
3067 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3068 } else {
3069 lists[list] = malloc(len);
3070 if (lists[list] == NULL)
3071 goto out;
3072 strcpy(lists[list], s);
3073 }
3074
3075 if (!sep)
3076 break;
3077
3078 *sep = ',';
3079 s = sep + 1;
3080 }
3081
3082 if (lists[1] != NULL) {
3083 struct strlist_config slist_config = {
3084 .dirname = strace_groups_dir,
3085 };
3086
3087 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3088 if (trace->ev_qualifier == NULL) {
3089 fputs("Not enough memory to parse event qualifier", trace->output);
3090 goto out;
3091 }
3092
3093 if (trace__validate_ev_qualifier(trace))
3094 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003095 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003096 }
3097
3098 err = 0;
3099
3100 if (lists[0]) {
3101 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3102 "event selector. use 'perf list' to list available events",
3103 parse_events_option);
3104 err = parse_events_option(&o, lists[0], 0);
3105 }
3106out:
3107 if (sep)
3108 *sep = ',';
3109
3110 return err;
3111}
3112
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003113static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3114{
3115 struct trace *trace = opt->value;
3116
3117 if (!list_empty(&trace->evlist->entries))
3118 return parse_cgroups(opt, str, unset);
3119
3120 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3121
3122 return 0;
3123}
3124
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003125int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003126{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003127 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003128 "perf trace [<options>] [<command>]",
3129 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003130 "perf trace record [<options>] [<command>]",
3131 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003132 NULL
3133 };
3134 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003135 .syscalls = {
3136 . max = -1,
3137 },
3138 .opts = {
3139 .target = {
3140 .uid = UINT_MAX,
3141 .uses_mmap = true,
3142 },
3143 .user_freq = UINT_MAX,
3144 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003145 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003146 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003147 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003148 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003149 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003150 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003151 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003152 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003153 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003154 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003155 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003156 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003157 OPT_CALLBACK('e', "event", &trace, "event",
3158 "event/syscall selector. use 'perf list' to list available events",
3159 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003160 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3161 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003162 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003163 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3164 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003165 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003166 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003167 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3168 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003169 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003170 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003171 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3172 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003173 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003174 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003175 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003176 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003177 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003178 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003179 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3180 "number of mmap data pages",
3181 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003182 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003183 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003184 OPT_CALLBACK(0, "duration", &trace, "float",
3185 "show only events with duration > N.M ms",
3186 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003187 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003188 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003189 OPT_BOOLEAN('T', "time", &trace.full_time,
3190 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003191 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3192 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003193 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3194 "Show only syscall summary with statistics"),
3195 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3196 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003197 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3198 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003199 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003200 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003201 OPT_CALLBACK(0, "call-graph", &trace.opts,
3202 "record_mode[,record_size]", record_callchain_help,
3203 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003204 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3205 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003206 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3207 "Set the minimum stack depth when parsing the callchain, "
3208 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003209 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3210 "Set the maximum stack depth when parsing the callchain, "
3211 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003212 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003213 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3214 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003215 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3216 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003217 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3218 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003219 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3220 "ms to wait before starting measurement after program "
3221 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003222 OPT_END()
3223 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003224 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003225 bool mmap_pages_user_set = true;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003226 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003227 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003228 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003229
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003230 signal(SIGSEGV, sighandler_dump_stack);
3231 signal(SIGFPE, sighandler_dump_stack);
3232
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003233 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003234 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003235
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003236 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003237 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003238 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003239 goto out;
3240 }
3241
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003242 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3243 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003244
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003245 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3246 usage_with_options_msg(trace_usage, trace_options,
3247 "cgroup monitoring only available in system-wide mode");
3248 }
3249
Wang Nand7888572016-04-08 15:07:24 +00003250 err = bpf__setup_stdout(trace.evlist);
3251 if (err) {
3252 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3253 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3254 goto out;
3255 }
3256
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003257 err = -1;
3258
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003259 if (trace.trace_pgfaults) {
3260 trace.opts.sample_address = true;
3261 trace.opts.sample_time = true;
3262 }
3263
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003264 if (trace.opts.mmap_pages == UINT_MAX)
3265 mmap_pages_user_set = false;
3266
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003267 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003268 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003269 max_stack_user_set = false;
3270 }
3271
3272#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003273 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003274 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003275 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003276#endif
3277
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003278 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003279 if (!mmap_pages_user_set && geteuid() == 0)
3280 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3281
Milian Wolff566a0882016-04-08 13:34:15 +02003282 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003283 }
Milian Wolff566a0882016-04-08 13:34:15 +02003284
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003285 if (trace.evlist->nr_entries > 0) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003286 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003287 if (evlist__set_syscall_tp_fields(trace.evlist)) {
3288 perror("failed to set syscalls:* tracepoint fields");
3289 goto out;
3290 }
3291 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003292
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003293 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3294 return trace__record(&trace, argc-1, &argv[1]);
3295
3296 /* summary_only implies summary option, but don't overwrite summary if set */
3297 if (trace.summary_only)
3298 trace.summary = trace.summary_only;
3299
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003300 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3301 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003302 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003303 }
3304
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003305 if (output_name != NULL) {
3306 err = trace__open_output(&trace, output_name);
3307 if (err < 0) {
3308 perror("failed to create output file");
3309 goto out;
3310 }
3311 }
3312
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003313 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003314 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003315 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003316 fprintf(trace.output, "%s", bf);
3317 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003318 }
3319
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003320 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003321 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003322 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003323 fprintf(trace.output, "%s", bf);
3324 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003325 }
3326
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003327 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003328 trace.opts.target.system_wide = true;
3329
David Ahern6810fc92013-08-28 22:29:52 -06003330 if (input_name)
3331 err = trace__replay(&trace);
3332 else
3333 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003334
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003335out_close:
3336 if (output_name != NULL)
3337 fclose(trace.output);
3338out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003339 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003340}