blob: bcf882afd6d08c968d2318b2c7453d71dca70ecd [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,
Arnaldo Carvalho de Melod3d1c4bdf52018-08-07 16:21:44 -030080 *sys_exit,
81 *augmented;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030082 } events;
83 } syscalls;
84 struct record_opts opts;
85 struct perf_evlist *evlist;
86 struct machine *host;
87 struct thread *current;
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -030088 struct cgroup *cgroup;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030089 u64 base_time;
90 FILE *output;
91 unsigned long nr_events;
92 struct strlist *ev_qualifier;
93 struct {
94 size_t nr;
95 int *entries;
96 } ev_qualifier_ids;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -030097 struct {
98 size_t nr;
99 pid_t *entries;
100 } filter_pids;
101 double duration_filter;
102 double runtime_ms;
103 struct {
104 u64 vfs_getname,
105 proc_getname;
106 } stats;
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -0300107 unsigned int max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -0300108 unsigned int min_stack;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300109 bool not_ev_qualifier;
110 bool live;
111 bool full_time;
112 bool sched;
113 bool multiple_threads;
114 bool summary;
115 bool summary_only;
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -0300116 bool failure_only;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300117 bool show_comm;
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -0300118 bool print_sample;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300119 bool show_tool_stats;
120 bool trace_syscalls;
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -0300121 bool kernel_syscallchains;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300122 bool force;
123 bool vfs_getname;
124 int trace_pgfaults;
125};
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300126
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300127struct tp_field {
128 int offset;
129 union {
130 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
131 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
132 };
133};
134
135#define TP_UINT_FIELD(bits) \
136static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
137{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500138 u##bits value; \
139 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
140 return value; \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300141}
142
143TP_UINT_FIELD(8);
144TP_UINT_FIELD(16);
145TP_UINT_FIELD(32);
146TP_UINT_FIELD(64);
147
148#define TP_UINT_FIELD__SWAPPED(bits) \
149static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
150{ \
David Ahern55d43bca2015-02-19 15:00:22 -0500151 u##bits value; \
152 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300153 return bswap_##bits(value);\
154}
155
156TP_UINT_FIELD__SWAPPED(16);
157TP_UINT_FIELD__SWAPPED(32);
158TP_UINT_FIELD__SWAPPED(64);
159
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300160static 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 -0300161{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300162 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300163
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300164 switch (size) {
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300165 case 1:
166 field->integer = tp_field__u8;
167 break;
168 case 2:
169 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
170 break;
171 case 4:
172 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
173 break;
174 case 8:
175 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
176 break;
177 default:
178 return -1;
179 }
180
181 return 0;
182}
183
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300184static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap)
185{
186 return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap);
187}
188
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300189static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
190{
191 return sample->raw_data + field->offset;
192}
193
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300194static int __tp_field__init_ptr(struct tp_field *field, int offset)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300195{
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300196 field->offset = offset;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300197 field->pointer = tp_field__ptr;
198 return 0;
199}
200
Arnaldo Carvalho de Meloaa823f52018-08-02 15:03:02 -0300201static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
202{
203 return __tp_field__init_ptr(field, format_field->offset);
204}
205
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300206struct syscall_tp {
207 struct tp_field id;
208 union {
209 struct tp_field args, ret;
210 };
211};
212
213static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
214 struct tp_field *field,
215 const char *name)
216{
217 struct format_field *format_field = perf_evsel__field(evsel, name);
218
219 if (format_field == NULL)
220 return -1;
221
222 return tp_field__init_uint(field, format_field, evsel->needs_swap);
223}
224
225#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
226 ({ struct syscall_tp *sc = evsel->priv;\
227 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
228
229static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
230 struct tp_field *field,
231 const char *name)
232{
233 struct format_field *format_field = perf_evsel__field(evsel, name);
234
235 if (format_field == NULL)
236 return -1;
237
238 return tp_field__init_ptr(field, format_field);
239}
240
241#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
242 ({ struct syscall_tp *sc = evsel->priv;\
243 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
244
245static void perf_evsel__delete_priv(struct perf_evsel *evsel)
246{
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300247 zfree(&evsel->priv);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300248 perf_evsel__delete(evsel);
249}
250
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -0300251static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel)
252{
253 struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
254
255 if (evsel->priv != NULL) {
256 if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr"))
257 goto out_delete;
258 return 0;
259 }
260
261 return -ENOMEM;
262out_delete:
263 zfree(&evsel->priv);
264 return -ENOENT;
265}
266
Arnaldo Carvalho de Melod3d1c4bdf52018-08-07 16:21:44 -0300267static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel)
268{
269 struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp));
270
271 if (evsel->priv != NULL) { /* field, sizeof_field, offsetof_field */
272 if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap))
273 goto out_delete;
274
275 return 0;
276 }
277
278 return -ENOMEM;
279out_delete:
280 zfree(&evsel->priv);
281 return -EINVAL;
282}
283
284static int perf_evsel__init_augmented_syscall_tp_args(struct perf_evsel *evsel)
285{
286 struct syscall_tp *sc = evsel->priv;
287
288 return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64));
289}
290
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300291static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler)
Namhyung Kim96695d42013-11-12 08:51:45 -0300292{
293 evsel->priv = malloc(sizeof(struct syscall_tp));
294 if (evsel->priv != NULL) {
295 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
296 goto out_delete;
297
298 evsel->handler = handler;
299 return 0;
300 }
301
302 return -ENOMEM;
303
304out_delete:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300305 zfree(&evsel->priv);
Namhyung Kim96695d42013-11-12 08:51:45 -0300306 return -ENOENT;
307}
308
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300309static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler)
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300310{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -0300311 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300312
David Ahern9aca7f12013-12-04 19:41:39 -0700313 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200314 if (IS_ERR(evsel))
David Ahern9aca7f12013-12-04 19:41:39 -0700315 evsel = perf_evsel__newtp("syscalls", direction);
316
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200317 if (IS_ERR(evsel))
318 return NULL;
319
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -0300320 if (perf_evsel__init_raw_syscall_tp(evsel, handler))
Jiri Olsa8dd2a132015-09-07 10:38:06 +0200321 goto out_delete;
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -0300322
323 return evsel;
324
325out_delete:
326 perf_evsel__delete_priv(evsel);
327 return NULL;
328}
329
330#define perf_evsel__sc_tp_uint(evsel, name, sample) \
331 ({ struct syscall_tp *fields = evsel->priv; \
332 fields->name.integer(&fields->name, sample); })
333
334#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
335 ({ struct syscall_tp *fields = evsel->priv; \
336 fields->name.pointer(&fields->name, sample); })
337
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300338size_t strarray__scnprintf(struct strarray *sa, char *bf, size_t size, const char *intfmt, int val)
339{
340 int idx = val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300341
Arnaldo Carvalho de Melobc972ad2018-07-26 15:30:33 -0300342 if (idx < 0 || idx >= sa->nr_entries || sa->entries[idx] == NULL)
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300343 return scnprintf(bf, size, intfmt, val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300344
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300345 return scnprintf(bf, size, "%s", sa->entries[idx]);
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300346}
347
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300348static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
349 const char *intfmt,
350 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300351{
Arnaldo Carvalho de Melo0ae79632017-07-17 10:31:42 -0300352 return strarray__scnprintf(arg->parm, bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300353}
354
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -0300355static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
356 struct syscall_arg *arg)
357{
358 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
359}
360
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300361#define SCA_STRARRAY syscall_arg__scnprintf_strarray
362
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300363struct strarrays {
364 int nr_entries;
365 struct strarray **entries;
366};
367
368#define DEFINE_STRARRAYS(array) struct strarrays strarrays__##array = { \
369 .nr_entries = ARRAY_SIZE(array), \
370 .entries = array, \
371}
372
Arnaldo Carvalho de Melo274e86f2017-07-14 09:38:38 -0300373size_t syscall_arg__scnprintf_strarrays(char *bf, size_t size,
374 struct syscall_arg *arg)
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300375{
376 struct strarrays *sas = arg->parm;
377 int i;
378
379 for (i = 0; i < sas->nr_entries; ++i) {
380 struct strarray *sa = sas->entries[i];
381 int idx = arg->val - sa->offset;
382
383 if (idx >= 0 && idx < sa->nr_entries) {
384 if (sa->entries[idx] == NULL)
385 break;
386 return scnprintf(bf, size, "%s", sa->entries[idx]);
387 }
388 }
389
390 return scnprintf(bf, size, "%d", arg->val);
391}
392
Arnaldo Carvalho de Melo48e1f912016-07-05 14:43:27 -0300393#ifndef AT_FDCWD
394#define AT_FDCWD -100
395#endif
396
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300397static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
398 struct syscall_arg *arg)
399{
400 int fd = arg->val;
401
402 if (fd == AT_FDCWD)
403 return scnprintf(bf, size, "CWD");
404
405 return syscall_arg__scnprintf_fd(bf, size, arg);
406}
407
408#define SCA_FDAT syscall_arg__scnprintf_fd_at
409
410static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
411 struct syscall_arg *arg);
412
413#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
414
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300415size_t syscall_arg__scnprintf_hex(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300416{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300417 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300418}
419
Arnaldo Carvalho de Melo2c2b1622017-07-14 10:19:18 -0300420size_t syscall_arg__scnprintf_int(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Meloa1c25522015-06-11 22:47:54 -0300421{
422 return scnprintf(bf, size, "%d", arg->val);
423}
424
Arnaldo Carvalho de Melo5dde91e2017-07-14 10:34:16 -0300425size_t syscall_arg__scnprintf_long(char *bf, size_t size, struct syscall_arg *arg)
426{
427 return scnprintf(bf, size, "%ld", arg->val);
428}
429
Arnaldo Carvalho de Melo729a7842015-10-29 11:48:18 -0300430static const char *bpf_cmd[] = {
431 "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM",
432 "MAP_GET_NEXT_KEY", "PROG_LOAD",
433};
434static DEFINE_STRARRAY(bpf_cmd);
435
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300436static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
437static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300438
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300439static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
440static DEFINE_STRARRAY(itimers);
441
Arnaldo Carvalho de Melob62bee12015-08-11 11:05:36 -0300442static const char *keyctl_options[] = {
443 "GET_KEYRING_ID", "JOIN_SESSION_KEYRING", "UPDATE", "REVOKE", "CHOWN",
444 "SETPERM", "DESCRIBE", "CLEAR", "LINK", "UNLINK", "SEARCH", "READ",
445 "INSTANTIATE", "NEGATE", "SET_REQKEY_KEYRING", "SET_TIMEOUT",
446 "ASSUME_AUTHORITY", "GET_SECURITY", "SESSION_TO_PARENT", "REJECT",
447 "INSTANTIATE_IOV", "INVALIDATE", "GET_PERSISTENT",
448};
449static DEFINE_STRARRAY(keyctl_options);
450
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300451static const char *whences[] = { "SET", "CUR", "END",
452#ifdef SEEK_DATA
453"DATA",
454#endif
455#ifdef SEEK_HOLE
456"HOLE",
457#endif
458};
459static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300460
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300461static const char *fcntl_cmds[] = {
462 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
Arnaldo Carvalho de Meloe000e5e2017-07-13 13:07:00 -0300463 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "GETLK64",
464 "SETLK64", "SETLKW64", "SETOWN_EX", "GETOWN_EX",
465 "GETOWNER_UIDS",
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300466};
467static DEFINE_STRARRAY(fcntl_cmds);
468
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300469static const char *fcntl_linux_specific_cmds[] = {
470 "SETLEASE", "GETLEASE", "NOTIFY", [5] = "CANCELLK", "DUPFD_CLOEXEC",
471 "SETPIPE_SZ", "GETPIPE_SZ", "ADD_SEALS", "GET_SEALS",
Arnaldo Carvalho de Melo64e45612017-07-13 17:34:46 -0300472 "GET_RW_HINT", "SET_RW_HINT", "GET_FILE_RW_HINT", "SET_FILE_RW_HINT",
Arnaldo Carvalho de Melo83a51692017-07-13 17:14:11 -0300473};
474
475static DEFINE_STRARRAY_OFFSET(fcntl_linux_specific_cmds, F_LINUX_SPECIFIC_BASE);
476
477static struct strarray *fcntl_cmds_arrays[] = {
478 &strarray__fcntl_cmds,
479 &strarray__fcntl_linux_specific_cmds,
480};
481
482static DEFINE_STRARRAYS(fcntl_cmds_arrays);
483
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300484static const char *rlimit_resources[] = {
485 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
486 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
487 "RTTIME",
488};
489static DEFINE_STRARRAY(rlimit_resources);
490
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300491static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
492static DEFINE_STRARRAY(sighow);
493
David Ahern4f8c1b72013-09-22 19:45:00 -0600494static const char *clockid[] = {
495 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
Arnaldo Carvalho de Melo28ebb872015-08-11 10:38:38 -0300496 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
497 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
David Ahern4f8c1b72013-09-22 19:45:00 -0600498};
499static DEFINE_STRARRAY(clockid);
500
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300501static const char *socket_families[] = {
502 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
503 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
504 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
505 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
506 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
507 "ALG", "NFC", "VSOCK",
508};
509static DEFINE_STRARRAY(socket_families);
510
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300511static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
512 struct syscall_arg *arg)
513{
514 size_t printed = 0;
515 int mode = arg->val;
516
517 if (mode == F_OK) /* 0 */
518 return scnprintf(bf, size, "F");
519#define P_MODE(n) \
520 if (mode & n##_OK) { \
521 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
522 mode &= ~n##_OK; \
523 }
524
525 P_MODE(R);
526 P_MODE(W);
527 P_MODE(X);
528#undef P_MODE
529
530 if (mode)
531 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
532
533 return printed;
534}
535
536#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
537
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300538static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
539 struct syscall_arg *arg);
540
541#define SCA_FILENAME syscall_arg__scnprintf_filename
542
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300543static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
544 struct syscall_arg *arg)
545{
546 int printed = 0, flags = arg->val;
547
548#define P_FLAG(n) \
549 if (flags & O_##n) { \
550 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
551 flags &= ~O_##n; \
552 }
553
554 P_FLAG(CLOEXEC);
555 P_FLAG(NONBLOCK);
556#undef P_FLAG
557
558 if (flags)
559 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
560
561 return printed;
562}
563
564#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
565
Arnaldo Carvalho de Meloa355a612016-04-13 11:55:18 -0300566#ifndef GRND_NONBLOCK
567#define GRND_NONBLOCK 0x0001
568#endif
569#ifndef GRND_RANDOM
570#define GRND_RANDOM 0x0002
571#endif
572
Arnaldo Carvalho de Melo39878d42016-03-30 20:02:15 -0300573static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
574 struct syscall_arg *arg)
575{
576 int printed = 0, flags = arg->val;
577
578#define P_FLAG(n) \
579 if (flags & GRND_##n) { \
580 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
581 flags &= ~GRND_##n; \
582 }
583
584 P_FLAG(RANDOM);
585 P_FLAG(NONBLOCK);
586#undef P_FLAG
587
588 if (flags)
589 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
590
591 return printed;
592}
593
594#define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags
595
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300596#define STRARRAY(name, array) \
597 { .scnprintf = SCA_STRARRAY, \
598 .parm = &strarray__##array, }
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300599
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +0100600#include "trace/beauty/arch_errno_names.c"
Arnaldo Carvalho de Meloea8dc3c2016-04-13 12:10:19 -0300601#include "trace/beauty/eventfd.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300602#include "trace/beauty/futex_op.c"
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300603#include "trace/beauty/futex_val3.c"
Arnaldo Carvalho de Melodf4cb162016-04-13 12:05:44 -0300604#include "trace/beauty/mmap.c"
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -0300605#include "trace/beauty/mode_t.c"
Arnaldo Carvalho de Meloa30e6252016-04-27 19:01:52 -0300606#include "trace/beauty/msg_flags.c"
Arnaldo Carvalho de Melo8f48df62016-05-06 10:02:32 -0300607#include "trace/beauty/open_flags.c"
Arnaldo Carvalho de Melo62de3442016-04-26 11:03:03 -0300608#include "trace/beauty/perf_event_open.c"
Arnaldo Carvalho de Melod5d71e82016-05-06 12:45:25 -0300609#include "trace/beauty/pid.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300610#include "trace/beauty/sched_policy.c"
Arnaldo Carvalho de Melof5cd95e2016-05-11 10:32:20 -0300611#include "trace/beauty/seccomp.c"
Arnaldo Carvalho de Melo12199d82016-05-06 09:58:02 -0300612#include "trace/beauty/signum.c"
Arnaldo Carvalho de Melobbf86c42016-04-14 13:53:10 -0300613#include "trace/beauty/socket_type.c"
Arnaldo Carvalho de Melo7206b902016-04-06 14:11:36 -0300614#include "trace/beauty/waitid_options.c"
Arnaldo Carvalho de Meloa3bca912016-04-06 12:51:33 -0300615
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300616struct syscall_arg_fmt {
617 size_t (*scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
618 void *parm;
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -0300619 const char *name;
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -0300620 bool show_zero;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300621};
622
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300623static struct syscall_fmt {
624 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300625 const char *alias;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300626 struct syscall_arg_fmt arg[6];
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -0300627 u8 nr_args;
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300628 bool errpid;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300629 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300630 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300631} syscall_fmts[] = {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300632 { .name = "access",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300633 .arg = { [1] = { .scnprintf = SCA_ACCMODE, /* mode */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300634 { .name = "bpf",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300635 .arg = { [0] = STRARRAY(cmd, bpf_cmd), }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300636 { .name = "brk", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300637 .arg = { [0] = { .scnprintf = SCA_HEX, /* brk */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300638 { .name = "clock_gettime",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300639 .arg = { [0] = STRARRAY(clk_id, clockid), }, },
Arnaldo Carvalho de Melo33396a32017-07-19 16:15:17 -0300640 { .name = "clone", .errpid = true, .nr_args = 5,
641 .arg = { [0] = { .name = "flags", .scnprintf = SCA_CLONE_FLAGS, },
642 [1] = { .name = "child_stack", .scnprintf = SCA_HEX, },
643 [2] = { .name = "parent_tidptr", .scnprintf = SCA_HEX, },
644 [3] = { .name = "child_tidptr", .scnprintf = SCA_HEX, },
645 [4] = { .name = "tls", .scnprintf = SCA_HEX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300646 { .name = "close",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300647 .arg = { [0] = { .scnprintf = SCA_CLOSE_FD, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300648 { .name = "epoll_ctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300649 .arg = { [1] = STRARRAY(op, epoll_ctl_ops), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300650 { .name = "eventfd2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300651 .arg = { [1] = { .scnprintf = SCA_EFD_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300652 { .name = "fchmodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300653 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300654 { .name = "fchownat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300655 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300656 { .name = "fcntl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300657 .arg = { [1] = { .scnprintf = SCA_FCNTL_CMD, /* cmd */
Arnaldo Carvalho de Melo39cc3552017-07-17 16:02:52 -0300658 .parm = &strarrays__fcntl_cmds_arrays,
659 .show_zero = true, },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300660 [2] = { .scnprintf = SCA_FCNTL_ARG, /* arg */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300661 { .name = "flock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300662 .arg = { [1] = { .scnprintf = SCA_FLOCK, /* cmd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300663 { .name = "fstat", .alias = "newfstat", },
664 { .name = "fstatat", .alias = "newfstatat", },
665 { .name = "futex",
Arnaldo Carvalho de Melo3258abe2018-01-22 12:56:59 -0300666 .arg = { [1] = { .scnprintf = SCA_FUTEX_OP, /* op */ },
667 [5] = { .scnprintf = SCA_FUTEX_VAL3, /* val3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300668 { .name = "futimesat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300669 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300670 { .name = "getitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300671 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300672 { .name = "getpid", .errpid = true, },
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -0300673 { .name = "getpgid", .errpid = true, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300674 { .name = "getppid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300675 { .name = "getrandom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300676 .arg = { [2] = { .scnprintf = SCA_GETRANDOM_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300677 { .name = "getrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300678 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo2d1073d2018-01-09 12:03:47 -0300679 { .name = "gettid", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300680 { .name = "ioctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300681 .arg = {
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300682#if defined(__i386__) || defined(__x86_64__)
683/*
684 * FIXME: Make this available to all arches.
685 */
Arnaldo Carvalho de Melo1cc47f22017-07-31 13:20:14 -0300686 [1] = { .scnprintf = SCA_IOCTL_CMD, /* cmd */ },
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300687 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300688#else
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300689 [2] = { .scnprintf = SCA_HEX, /* arg */ }, }, },
Arnaldo Carvalho de Melo844ae5b2014-02-10 14:09:48 -0300690#endif
Arnaldo Carvalho de Melo1de30382017-10-31 11:32:23 -0300691 { .name = "kcmp", .nr_args = 5,
692 .arg = { [0] = { .name = "pid1", .scnprintf = SCA_PID, },
693 [1] = { .name = "pid2", .scnprintf = SCA_PID, },
694 [2] = { .name = "type", .scnprintf = SCA_KCMP_TYPE, },
695 [3] = { .name = "idx1", .scnprintf = SCA_KCMP_IDX, },
696 [4] = { .name = "idx2", .scnprintf = SCA_KCMP_IDX, }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300697 { .name = "keyctl",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300698 .arg = { [0] = STRARRAY(option, keyctl_options), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300699 { .name = "kill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300700 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300701 { .name = "linkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300702 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300703 { .name = "lseek",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300704 .arg = { [2] = STRARRAY(whence, whences), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300705 { .name = "lstat", .alias = "newlstat", },
706 { .name = "madvise",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300707 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
708 [2] = { .scnprintf = SCA_MADV_BHV, /* behavior */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300709 { .name = "mkdirat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300710 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300711 { .name = "mknodat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300712 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300713 { .name = "mlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300714 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300715 { .name = "mlockall",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300716 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300717 { .name = "mmap", .hexret = true,
Jiri Olsa54265662017-05-31 13:35:57 +0200718/* The standard mmap maps to old_mmap on s390x */
719#if defined(__s390x__)
720 .alias = "old_mmap",
721#endif
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300722 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
723 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
724 [3] = { .scnprintf = SCA_MMAP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300725 { .name = "mprotect",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300726 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
727 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300728 { .name = "mq_unlink",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300729 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* u_name */ }, }, },
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300730 { .name = "mremap", .hexret = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300731 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ },
732 [3] = { .scnprintf = SCA_MREMAP_FLAGS, /* flags */ },
733 [4] = { .scnprintf = SCA_HEX, /* new_addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300734 { .name = "munlock",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300735 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300736 { .name = "munmap",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300737 .arg = { [0] = { .scnprintf = SCA_HEX, /* addr */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300738 { .name = "name_to_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300739 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300740 { .name = "newfstatat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300741 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300742 { .name = "open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300743 .arg = { [1] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300744 { .name = "open_by_handle_at",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300745 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
746 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300747 { .name = "openat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300748 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ },
749 [2] = { .scnprintf = SCA_OPEN_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300750 { .name = "perf_event_open",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300751 .arg = { [2] = { .scnprintf = SCA_INT, /* cpu */ },
752 [3] = { .scnprintf = SCA_FD, /* group_fd */ },
753 [4] = { .scnprintf = SCA_PERF_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300754 { .name = "pipe2",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300755 .arg = { [1] = { .scnprintf = SCA_PIPE_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo83bc9c372017-08-28 11:47:11 -0300756 { .name = "pkey_alloc",
757 .arg = { [1] = { .scnprintf = SCA_PKEY_ALLOC_ACCESS_RIGHTS, /* access_rights */ }, }, },
758 { .name = "pkey_free",
759 .arg = { [0] = { .scnprintf = SCA_INT, /* key */ }, }, },
760 { .name = "pkey_mprotect",
761 .arg = { [0] = { .scnprintf = SCA_HEX, /* start */ },
762 [2] = { .scnprintf = SCA_MMAP_PROT, /* prot */ },
763 [3] = { .scnprintf = SCA_INT, /* pkey */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300764 { .name = "poll", .timeout = true, },
765 { .name = "ppoll", .timeout = true, },
Arnaldo Carvalho de Melod688d032017-10-26 15:19:35 -0300766 { .name = "prctl", .alias = "arch_prctl",
767 .arg = { [0] = { .scnprintf = SCA_PRCTL_OPTION, /* option */ },
768 [1] = { .scnprintf = SCA_PRCTL_ARG2, /* arg2 */ },
769 [2] = { .scnprintf = SCA_PRCTL_ARG3, /* arg3 */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300770 { .name = "pread", .alias = "pread64", },
771 { .name = "preadv", .alias = "pread", },
772 { .name = "prlimit64",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300773 .arg = { [1] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300774 { .name = "pwrite", .alias = "pwrite64", },
775 { .name = "readlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300776 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300777 { .name = "recvfrom",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300778 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300779 { .name = "recvmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300780 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300781 { .name = "recvmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300782 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300783 { .name = "renameat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300784 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300785 { .name = "rt_sigaction",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300786 .arg = { [0] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300787 { .name = "rt_sigprocmask",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300788 .arg = { [0] = STRARRAY(how, sighow), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300789 { .name = "rt_sigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300790 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300791 { .name = "rt_tgsigqueueinfo",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300792 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300793 { .name = "sched_setscheduler",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300794 .arg = { [1] = { .scnprintf = SCA_SCHED_POLICY, /* policy */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300795 { .name = "seccomp",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300796 .arg = { [0] = { .scnprintf = SCA_SECCOMP_OP, /* op */ },
797 [1] = { .scnprintf = SCA_SECCOMP_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300798 { .name = "select", .timeout = true, },
799 { .name = "sendmmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300800 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300801 { .name = "sendmsg",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300802 .arg = { [2] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300803 { .name = "sendto",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300804 .arg = { [3] = { .scnprintf = SCA_MSG_FLAGS, /* flags */ }, }, },
Arnaldo Carvalho de Meloc65f1072016-04-06 14:55:18 -0300805 { .name = "set_tid_address", .errpid = true, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300806 { .name = "setitimer",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300807 .arg = { [0] = STRARRAY(which, itimers), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300808 { .name = "setrlimit",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300809 .arg = { [0] = STRARRAY(resource, rlimit_resources), }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300810 { .name = "socket",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300811 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300812 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
813 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300814 { .name = "socketpair",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300815 .arg = { [0] = STRARRAY(family, socket_families),
Arnaldo Carvalho de Melo162d3ed2018-07-26 09:26:13 -0300816 [1] = { .scnprintf = SCA_SK_TYPE, /* type */ },
817 [2] = { .scnprintf = SCA_SK_PROTO, /* protocol */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300818 { .name = "stat", .alias = "newstat", },
819 { .name = "statx",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300820 .arg = { [0] = { .scnprintf = SCA_FDAT, /* fdat */ },
821 [2] = { .scnprintf = SCA_STATX_FLAGS, /* flags */ } ,
822 [3] = { .scnprintf = SCA_STATX_MASK, /* mask */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300823 { .name = "swapoff",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300824 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300825 { .name = "swapon",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300826 .arg = { [0] = { .scnprintf = SCA_FILENAME, /* specialfile */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300827 { .name = "symlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300828 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300829 { .name = "tgkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300830 .arg = { [2] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300831 { .name = "tkill",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300832 .arg = { [1] = { .scnprintf = SCA_SIGNUM, /* sig */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300833 { .name = "uname", .alias = "newuname", },
834 { .name = "unlinkat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300835 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dfd */ }, }, },
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -0300836 { .name = "utimensat",
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300837 .arg = { [0] = { .scnprintf = SCA_FDAT, /* dirfd */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300838 { .name = "wait4", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300839 .arg = { [2] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -0300840 { .name = "waitid", .errpid = true,
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300841 .arg = { [3] = { .scnprintf = SCA_WAITID_OPTIONS, /* options */ }, }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300842};
843
844static int syscall_fmt__cmp(const void *name, const void *fmtp)
845{
846 const struct syscall_fmt *fmt = fmtp;
847 return strcmp(name, fmt->name);
848}
849
850static struct syscall_fmt *syscall_fmt__find(const char *name)
851{
852 const int nmemb = ARRAY_SIZE(syscall_fmts);
853 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
854}
855
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300856/*
857 * is_exit: is this "exit" or "exit_group"?
858 * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter.
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -0300859 * args_size: sum of the sizes of the syscall arguments, anything after that is augmented stuff: pathname for openat, etc.
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300860 */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300861struct syscall {
862 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300863 int nr_args;
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -0300864 int args_size;
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300865 bool is_exit;
866 bool is_open;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300867 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300868 const char *name;
869 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300870 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300871};
872
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300873/*
874 * We need to have this 'calculated' boolean because in some cases we really
875 * don't know what is the duration of a syscall, for instance, when we start
876 * a session and some threads are waiting for a syscall to finish, say 'poll',
877 * in which case all we can do is to print "( ? ) for duration and for the
878 * start timestamp.
879 */
880static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200881{
882 double duration = (double)t / NSEC_PER_MSEC;
883 size_t printed = fprintf(fp, "(");
884
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300885 if (!calculated)
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -0300886 printed += fprintf(fp, " ");
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300887 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200888 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
889 else if (duration >= 0.01)
890 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
891 else
892 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300893 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200894}
895
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300896/**
897 * filename.ptr: The filename char pointer that will be vfs_getname'd
898 * filename.entry_str_pos: Where to insert the string translated from
899 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300900 * ret_scnprintf: syscall args may set this to a different syscall return
901 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300902 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300903struct thread_trace {
904 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300905 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300906 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400907 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300908 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300909 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300910 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300911 struct {
912 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300913 short int entry_str_pos;
914 bool pending_open;
915 unsigned int namelen;
916 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300917 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300918 struct {
919 int max;
920 char **table;
921 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600922
923 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300924};
925
926static struct thread_trace *thread_trace__new(void)
927{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300928 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
929
930 if (ttrace)
931 ttrace->paths.max = -1;
932
David Ahernbf2575c2013-10-08 21:26:53 -0600933 ttrace->syscall_stats = intlist__new(NULL);
934
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300935 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300936}
937
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300938static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300939{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300940 struct thread_trace *ttrace;
941
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300942 if (thread == NULL)
943 goto fail;
944
Namhyung Kim89dceb22014-10-06 09:46:03 +0900945 if (thread__priv(thread) == NULL)
946 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300947
Namhyung Kim89dceb22014-10-06 09:46:03 +0900948 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300949 goto fail;
950
Namhyung Kim89dceb22014-10-06 09:46:03 +0900951 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300952 ++ttrace->nr_events;
953
954 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300955fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300956 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300957 "WARNING: not enough memory, dropping samples!\n");
958 return NULL;
959}
960
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300961
962void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300963 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300964{
965 struct thread_trace *ttrace = thread__priv(arg->thread);
966
967 ttrace->ret_scnprintf = ret_scnprintf;
968}
969
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400970#define TRACE_PFMAJ (1 << 0)
971#define TRACE_PFMIN (1 << 1)
972
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300973static const size_t trace__entry_str_size = 2048;
974
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300975static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300976{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900977 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300978
979 if (fd > ttrace->paths.max) {
980 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
981
982 if (npath == NULL)
983 return -1;
984
985 if (ttrace->paths.max != -1) {
986 memset(npath + ttrace->paths.max + 1, 0,
987 (fd - ttrace->paths.max) * sizeof(char *));
988 } else {
989 memset(npath, 0, (fd + 1) * sizeof(char *));
990 }
991
992 ttrace->paths.table = npath;
993 ttrace->paths.max = fd;
994 }
995
996 ttrace->paths.table[fd] = strdup(pathname);
997
998 return ttrace->paths.table[fd] != NULL ? 0 : -1;
999}
1000
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -03001001static int thread__read_fd_path(struct thread *thread, int fd)
1002{
1003 char linkname[PATH_MAX], pathname[PATH_MAX];
1004 struct stat st;
1005 int ret;
1006
1007 if (thread->pid_ == thread->tid) {
1008 scnprintf(linkname, sizeof(linkname),
1009 "/proc/%d/fd/%d", thread->pid_, fd);
1010 } else {
1011 scnprintf(linkname, sizeof(linkname),
1012 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1013 }
1014
1015 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1016 return -1;
1017
1018 ret = readlink(linkname, pathname, sizeof(pathname));
1019
1020 if (ret < 0 || ret > st.st_size)
1021 return -1;
1022
1023 pathname[ret] = '\0';
1024 return trace__set_fd_pathname(thread, fd, pathname);
1025}
1026
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001027static const char *thread__fd_path(struct thread *thread, int fd,
1028 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001029{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001030 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001031
1032 if (ttrace == NULL)
1033 return NULL;
1034
1035 if (fd < 0)
1036 return NULL;
1037
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001038 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001039 if (!trace->live)
1040 return NULL;
1041 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001042 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001043 return NULL;
1044 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001045
1046 return ttrace->paths.table[fd];
1047}
1048
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001049size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001050{
1051 int fd = arg->val;
1052 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001053 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001054
1055 if (path)
1056 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1057
1058 return printed;
1059}
1060
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -03001061size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1062{
1063 size_t printed = scnprintf(bf, size, "%d", fd);
1064 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1065
1066 if (thread) {
1067 const char *path = thread__fd_path(thread, fd, trace);
1068
1069 if (path)
1070 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1071
1072 thread__put(thread);
1073 }
1074
1075 return printed;
1076}
1077
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001078static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1079 struct syscall_arg *arg)
1080{
1081 int fd = arg->val;
1082 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001083 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001084
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001085 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1086 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001087
1088 return printed;
1089}
1090
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001091static void thread__set_filename_pos(struct thread *thread, const char *bf,
1092 unsigned long ptr)
1093{
1094 struct thread_trace *ttrace = thread__priv(thread);
1095
1096 ttrace->filename.ptr = ptr;
1097 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1098}
1099
1100static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1101 struct syscall_arg *arg)
1102{
1103 unsigned long ptr = arg->val;
1104
1105 if (!arg->trace->vfs_getname)
1106 return scnprintf(bf, size, "%#x", ptr);
1107
1108 thread__set_filename_pos(arg->thread, bf, ptr);
1109 return 0;
1110}
1111
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001112static bool trace__filter_duration(struct trace *trace, double t)
1113{
1114 return t < (trace->duration_filter * NSEC_PER_MSEC);
1115}
1116
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001117static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001118{
1119 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1120
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001121 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001122}
1123
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001124/*
1125 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1126 * using ttrace->entry_time for a thread that receives a sys_exit without
1127 * first having received a sys_enter ("poll" issued before tracing session
1128 * starts, lost sys_enter exit due to ring buffer overflow).
1129 */
1130static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1131{
1132 if (tstamp > 0)
1133 return __trace__fprintf_tstamp(trace, tstamp, fp);
1134
1135 return fprintf(fp, " ? ");
1136}
1137
Namhyung Kimf15eb532012-10-05 14:02:16 +09001138static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001139static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001140
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001141static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001142{
1143 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001144 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001145}
1146
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001147static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001148 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001149{
1150 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001151 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001152
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001153 if (trace->multiple_threads) {
1154 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001155 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001156 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001157 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001158
1159 return printed;
1160}
1161
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001162static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001163 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001164{
1165 int ret = 0;
1166
1167 switch (event->header.type) {
1168 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001169 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001170 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001171 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001172 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001173 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001174 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001175 break;
1176 }
1177
1178 return ret;
1179}
1180
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001181static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001182 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001183 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001184 struct machine *machine)
1185{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001186 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001187 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001188}
1189
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001190static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1191{
1192 struct machine *machine = vmachine;
1193
1194 if (machine->kptr_restrict_warned)
1195 return NULL;
1196
1197 if (symbol_conf.kptr_restrict) {
1198 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1199 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1200 "Kernel samples will not be resolved.\n");
1201 machine->kptr_restrict_warned = true;
1202 return NULL;
1203 }
1204
1205 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1206}
1207
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001208static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1209{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001210 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001211
1212 if (err)
1213 return err;
1214
David Ahern8fb598e2013-09-28 13:13:00 -06001215 trace->host = machine__new_host();
1216 if (trace->host == NULL)
1217 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001218
Andrei Vagincbd5c172017-11-07 16:22:46 -08001219 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1220 if (err < 0)
1221 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001222
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001223 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001224 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001225 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001226out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001227 if (err)
1228 symbol__exit();
1229
1230 return err;
1231}
1232
Andrei Vagin33974a42017-11-07 16:22:45 -08001233static void trace__symbols__exit(struct trace *trace)
1234{
1235 machine__exit(trace->host);
1236 trace->host = NULL;
1237
1238 symbol__exit();
1239}
1240
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001241static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1242{
1243 int idx;
1244
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001245 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1246 nr_args = sc->fmt->nr_args;
1247
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001248 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1249 if (sc->arg_fmt == NULL)
1250 return -1;
1251
1252 for (idx = 0; idx < nr_args; ++idx) {
1253 if (sc->fmt)
1254 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1255 }
1256
1257 sc->nr_args = nr_args;
1258 return 0;
1259}
1260
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001261static int syscall__set_arg_fmts(struct syscall *sc)
1262{
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001263 struct format_field *field, *last_field = NULL;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001264 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001265
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001266 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001267 last_field = field;
1268
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001269 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1270 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001271
1272 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001273 (strcmp(field->name, "filename") == 0 ||
1274 strcmp(field->name, "path") == 0 ||
1275 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001276 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001277 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001278 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001279 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001280 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001281 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001282 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001283 else if ((strcmp(field->type, "int") == 0 ||
1284 strcmp(field->type, "unsigned int") == 0 ||
1285 strcmp(field->type, "long") == 0) &&
1286 (len = strlen(field->name)) >= 2 &&
1287 strcmp(field->name + len - 2, "fd") == 0) {
1288 /*
1289 * /sys/kernel/tracing/events/syscalls/sys_enter*
1290 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1291 * 65 int
1292 * 23 unsigned int
1293 * 7 unsigned long
1294 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001295 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001296 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001297 }
1298
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001299 if (last_field)
1300 sc->args_size = last_field->offset + last_field->size;
1301
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001302 return 0;
1303}
1304
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001305static int trace__read_syscall_info(struct trace *trace, int id)
1306{
1307 char tp_name[128];
1308 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001309 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001310
1311 if (name == NULL)
1312 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001313
1314 if (id > trace->syscalls.max) {
1315 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1316
1317 if (nsyscalls == NULL)
1318 return -1;
1319
1320 if (trace->syscalls.max != -1) {
1321 memset(nsyscalls + trace->syscalls.max + 1, 0,
1322 (id - trace->syscalls.max) * sizeof(*sc));
1323 } else {
1324 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1325 }
1326
1327 trace->syscalls.table = nsyscalls;
1328 trace->syscalls.max = id;
1329 }
1330
1331 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001332 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001333
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001334 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001335
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001336 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001337 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001338
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001339 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001340 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001341 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001342 }
1343
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001344 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1345 return -1;
1346
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001347 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001348 return -1;
1349
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001350 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001351 /*
1352 * We need to check and discard the first variable '__syscall_nr'
1353 * or 'nr' that mean the syscall number. It is needless here.
1354 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1355 */
1356 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001357 sc->args = sc->args->next;
1358 --sc->nr_args;
1359 }
1360
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001361 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001362 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001363
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001364 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001365}
1366
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001367static int trace__validate_ev_qualifier(struct trace *trace)
1368{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001369 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001370 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001371 struct str_node *pos;
1372
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001373 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1374 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1375 sizeof(trace->ev_qualifier_ids.entries[0]));
1376
1377 if (trace->ev_qualifier_ids.entries == NULL) {
1378 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1379 trace->output);
1380 err = -EINVAL;
1381 goto out;
1382 }
1383
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001384 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001385 i = 0;
1386
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001387 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001388 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001389 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001390
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001391 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001392 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1393 if (id >= 0)
1394 goto matches;
1395
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001396 if (err == 0) {
1397 fputs("Error:\tInvalid syscall ", trace->output);
1398 err = -EINVAL;
1399 } else {
1400 fputs(", ", trace->output);
1401 }
1402
1403 fputs(sc, trace->output);
1404 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001405matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001406 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001407 if (match_next == -1)
1408 continue;
1409
1410 while (1) {
1411 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1412 if (id < 0)
1413 break;
1414 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1415 void *entries;
1416
1417 nr_allocated += 8;
1418 entries = realloc(trace->ev_qualifier_ids.entries,
1419 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1420 if (entries == NULL) {
1421 err = -ENOMEM;
1422 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1423 goto out_free;
1424 }
1425 trace->ev_qualifier_ids.entries = entries;
1426 }
1427 trace->ev_qualifier_ids.nr++;
1428 trace->ev_qualifier_ids.entries[i++] = id;
1429 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001430 }
1431
1432 if (err < 0) {
1433 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1434 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001435out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001436 zfree(&trace->ev_qualifier_ids.entries);
1437 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001438 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001439out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001440 return err;
1441}
1442
David Ahern55d43bca2015-02-19 15:00:22 -05001443/*
1444 * args is to be interpreted as a series of longs but we need to handle
1445 * 8-byte unaligned accesses. args points to raw_data within the event
1446 * and raw_data is guaranteed to be 8-byte unaligned because it is
1447 * preceded by raw_size which is a u32. So we need to copy args to a temp
1448 * variable to read it. Most notably this avoids extended load instructions
1449 * on unaligned addresses
1450 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001451unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001452{
1453 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001454 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001455
1456 memcpy(&val, p, sizeof(val));
1457 return val;
1458}
1459
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001460static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1461 struct syscall_arg *arg)
1462{
1463 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1464 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1465
1466 return scnprintf(bf, size, "arg%d: ", arg->idx);
1467}
1468
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001469static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1470 struct syscall_arg *arg, unsigned long val)
1471{
1472 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1473 arg->val = val;
1474 if (sc->arg_fmt[arg->idx].parm)
1475 arg->parm = sc->arg_fmt[arg->idx].parm;
1476 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1477 }
1478 return scnprintf(bf, size, "%ld", val);
1479}
1480
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001481static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001482 unsigned char *args, void *augmented_args, int augmented_args_size,
1483 struct trace *trace, struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001484{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001485 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001486 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001487 u8 bit = 1;
1488 struct syscall_arg arg = {
1489 .args = args,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001490 .augmented = {
1491 .size = augmented_args_size,
1492 .args = augmented_args,
1493 },
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001494 .idx = 0,
1495 .mask = 0,
1496 .trace = trace,
1497 .thread = thread,
1498 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001499 struct thread_trace *ttrace = thread__priv(thread);
1500
1501 /*
1502 * Things like fcntl will set this in its 'cmd' formatter to pick the
1503 * right formatter for the return value (an fd? file flags?), which is
1504 * not needed for syscalls that always return a given type, say an fd.
1505 */
1506 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001507
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001508 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001509 struct format_field *field;
1510
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001511 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001512 field = field->next, ++arg.idx, bit <<= 1) {
1513 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001514 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001515
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001516 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001517
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001518 /*
1519 * Suppress this argument if its value is zero and
1520 * and we don't have a string associated in an
1521 * strarray for it.
1522 */
David Ahern55d43bca2015-02-19 15:00:22 -05001523 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001524 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001525 (sc->arg_fmt[arg.idx].show_zero ||
1526 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001527 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1528 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001529 continue;
1530
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001531 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001532 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001533 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001534 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001535 } else if (IS_ERR(sc->tp_format)) {
1536 /*
1537 * If we managed to read the tracepoint /format file, then we
1538 * may end up not having any args, like with gettid(), so only
1539 * print the raw args when we didn't manage to read it.
1540 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001541 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001542 if (arg.mask & bit)
1543 goto next_arg;
1544 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001545 if (printed)
1546 printed += scnprintf(bf + printed, size - printed, ", ");
1547 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001548 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1549next_arg:
1550 ++arg.idx;
1551 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001552 }
1553 }
1554
1555 return printed;
1556}
1557
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001558typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001559 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001560 struct perf_sample *sample);
1561
1562static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001563 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001564{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001565
1566 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001567
1568 /*
1569 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1570 * before that, leaving at a higher verbosity level till that is
1571 * explained. Reproduced with plain ftrace with:
1572 *
1573 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1574 * grep "NR -1 " /t/trace_pipe
1575 *
1576 * After generating some load on the machine.
1577 */
1578 if (verbose > 1) {
1579 static u64 n;
1580 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1581 id, perf_evsel__name(evsel), ++n);
1582 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001583 return NULL;
1584 }
1585
1586 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1587 trace__read_syscall_info(trace, id))
1588 goto out_cant_read;
1589
1590 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1591 goto out_cant_read;
1592
1593 return &trace->syscalls.table[id];
1594
1595out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001596 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001597 fprintf(trace->output, "Problems reading syscall %d", id);
1598 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1599 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1600 fputs(" information\n", trace->output);
1601 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001602 return NULL;
1603}
1604
David Ahernbf2575c2013-10-08 21:26:53 -06001605static void thread__update_stats(struct thread_trace *ttrace,
1606 int id, struct perf_sample *sample)
1607{
1608 struct int_node *inode;
1609 struct stats *stats;
1610 u64 duration = 0;
1611
1612 inode = intlist__findnew(ttrace->syscall_stats, id);
1613 if (inode == NULL)
1614 return;
1615
1616 stats = inode->priv;
1617 if (stats == NULL) {
1618 stats = malloc(sizeof(struct stats));
1619 if (stats == NULL)
1620 return;
1621 init_stats(stats);
1622 inode->priv = stats;
1623 }
1624
1625 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1626 duration = sample->time - ttrace->entry_time;
1627
1628 update_stats(stats, duration);
1629}
1630
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001631static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001632{
1633 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001634 size_t printed;
1635
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001636 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001637 return 0;
1638
1639 ttrace = thread__priv(trace->current);
1640
1641 if (!ttrace->entry_pending)
1642 return 0;
1643
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001644 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001645 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1646 ttrace->entry_pending = false;
1647
1648 return printed;
1649}
1650
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001651static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1652 struct perf_sample *sample, struct thread *thread)
1653{
1654 int printed = 0;
1655
1656 if (trace->print_sample) {
1657 double ts = (double)sample->time / NSEC_PER_MSEC;
1658
1659 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1660 perf_evsel__name(evsel), ts,
1661 thread__comm_str(thread),
1662 sample->pid, sample->tid, sample->cpu);
1663 }
1664
1665 return printed;
1666}
1667
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001668static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001669 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001670 struct perf_sample *sample)
1671{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001672 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001673 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001674 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001675 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001676 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001677 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001678 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001679
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001680 if (sc == NULL)
1681 return -1;
1682
David Ahern8fb598e2013-09-28 13:13:00 -06001683 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001684 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001685 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001686 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001687
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001688 trace__fprintf_sample(trace, evsel, sample, thread);
1689
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001690 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001691
1692 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001693 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001694 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001695 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696 }
1697
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001698 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001699 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001700
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001701 ttrace->entry_time = sample->time;
1702 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001703 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001704
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001705 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001706 args, NULL, 0, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001707
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001708 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001709 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001710 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001711 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001712 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001713 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001714 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001715 /* See trace__vfs_getname & trace__sys_exit */
1716 ttrace->filename.pending_open = false;
1717 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001718
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001719 if (trace->current != thread) {
1720 thread__put(trace->current);
1721 trace->current = thread__get(thread);
1722 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001723 err = 0;
1724out_put:
1725 thread__put(thread);
1726 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001727}
1728
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001729static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1730 struct perf_sample *sample)
1731{
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001732 struct thread_trace *ttrace;
1733 struct thread *thread;
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001734 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
1735 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001736 char msg[1024];
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001737 void *args, *augmented_args = NULL;
1738 int augmented_args_size;
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001739
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001740 if (sc == NULL)
1741 return -1;
1742
1743 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1744 ttrace = thread__trace(thread, trace->output);
1745 /*
1746 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1747 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1748 */
1749 if (ttrace == NULL)
1750 goto out_put;
1751
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001752 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001753 augmented_args_size = sample->raw_size - sc->args_size;
1754 if (augmented_args_size > 0)
1755 augmented_args = sample->raw_data + sc->args_size;
1756
1757 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001758 fprintf(trace->output, "%s", msg);
1759 err = 0;
1760out_put:
1761 thread__put(thread);
1762 return err;
1763}
1764
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001765static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1766 struct perf_sample *sample,
1767 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001768{
1769 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301770 int max_stack = evsel->attr.sample_max_stack ?
1771 evsel->attr.sample_max_stack :
1772 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001773
1774 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301775 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001776 return -1;
1777
1778 return 0;
1779}
1780
1781static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1782{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001783 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001784 const unsigned int print_opts = EVSEL__PRINT_SYM |
1785 EVSEL__PRINT_DSO |
1786 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001787
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001788 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001789}
1790
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001791static const char *errno_to_name(struct perf_evsel *evsel, int err)
1792{
1793 struct perf_env *env = perf_evsel__env(evsel);
1794 const char *arch_name = perf_env__arch(env);
1795
1796 return arch_syscalls__strerrno(arch_name, err);
1797}
1798
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001799static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001800 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001801 struct perf_sample *sample)
1802{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001803 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001804 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001805 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001806 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001807 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001808 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001809 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001810
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001811 if (sc == NULL)
1812 return -1;
1813
David Ahern8fb598e2013-09-28 13:13:00 -06001814 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001815 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001816 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001817 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001818
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001819 trace__fprintf_sample(trace, evsel, sample, thread);
1820
David Ahernbf2575c2013-10-08 21:26:53 -06001821 if (trace->summary)
1822 thread__update_stats(ttrace, id, sample);
1823
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001824 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001825
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001826 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001827 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1828 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001829 ++trace->stats.vfs_getname;
1830 }
1831
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001832 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001833 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001834 if (trace__filter_duration(trace, duration))
1835 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001836 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001837 } else if (trace->duration_filter)
1838 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001839
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001840 if (sample->callchain) {
1841 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1842 if (callchain_ret == 0) {
1843 if (callchain_cursor.nr < trace->min_stack)
1844 goto out;
1845 callchain_ret = 1;
1846 }
1847 }
1848
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001849 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001850 goto out;
1851
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001852 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001853
1854 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001855 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001856 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001857 fprintf(trace->output, " ... [");
1858 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1859 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001860 }
1861
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001862 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001863 if (ret < 0)
1864 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001865signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001866 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001867 } else if (ret < 0) {
1868errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001869 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001870 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001871 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001872
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001873 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001874 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001875 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001876 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001877 else if (ttrace->ret_scnprintf) {
1878 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001879 struct syscall_arg arg = {
1880 .val = ret,
1881 .thread = thread,
1882 .trace = trace,
1883 };
1884 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001885 ttrace->ret_scnprintf = NULL;
1886 fprintf(trace->output, ") = %s", bf);
1887 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001888 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001889 else if (sc->fmt->errpid) {
1890 struct thread *child = machine__find_thread(trace->host, ret, ret);
1891
1892 if (child != NULL) {
1893 fprintf(trace->output, ") = %ld", ret);
1894 if (child->comm_set)
1895 fprintf(trace->output, " (%s)", thread__comm_str(child));
1896 thread__put(child);
1897 }
1898 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001899 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001900
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001901 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001902
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001903 if (callchain_ret > 0)
1904 trace__fprintf_callchain(trace, sample);
1905 else if (callchain_ret < 0)
1906 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001907out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001908 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001909 err = 0;
1910out_put:
1911 thread__put(thread);
1912 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001913}
1914
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001915static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001916 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001917 struct perf_sample *sample)
1918{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001919 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1920 struct thread_trace *ttrace;
1921 size_t filename_len, entry_str_len, to_move;
1922 ssize_t remaining_space;
1923 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001924 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001925
1926 if (!thread)
1927 goto out;
1928
1929 ttrace = thread__priv(thread);
1930 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001931 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001932
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001933 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001934 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001935 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001936
1937 if (ttrace->filename.namelen < filename_len) {
1938 char *f = realloc(ttrace->filename.name, filename_len + 1);
1939
1940 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001941 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001942
1943 ttrace->filename.namelen = filename_len;
1944 ttrace->filename.name = f;
1945 }
1946
1947 strcpy(ttrace->filename.name, filename);
1948 ttrace->filename.pending_open = true;
1949
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001950 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001951 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001952
1953 entry_str_len = strlen(ttrace->entry_str);
1954 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1955 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001956 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001957
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001958 if (filename_len > (size_t)remaining_space) {
1959 filename += filename_len - remaining_space;
1960 filename_len = remaining_space;
1961 }
1962
1963 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1964 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1965 memmove(pos + filename_len, pos, to_move);
1966 memcpy(pos, filename, filename_len);
1967
1968 ttrace->filename.ptr = 0;
1969 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001970out_put:
1971 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001972out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001973 return 0;
1974}
1975
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001976static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001977 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001978 struct perf_sample *sample)
1979{
1980 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1981 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001982 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001983 sample->pid,
1984 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001985 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001986
1987 if (ttrace == NULL)
1988 goto out_dump;
1989
1990 ttrace->runtime_ms += runtime_ms;
1991 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001992out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001993 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001994 return 0;
1995
1996out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001997 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001998 evsel->name,
1999 perf_evsel__strval(evsel, sample, "comm"),
2000 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2001 runtime,
2002 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002003 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002004}
2005
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002006static int bpf_output__printer(enum binary_printer_ops op,
2007 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00002008{
Wang Nan1d6c9402016-02-26 09:31:55 +00002009 unsigned char ch = (unsigned char)val;
2010
2011 switch (op) {
2012 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002013 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00002014 case BINARY_PRINT_DATA_BEGIN:
2015 case BINARY_PRINT_LINE_BEGIN:
2016 case BINARY_PRINT_ADDR:
2017 case BINARY_PRINT_NUM_DATA:
2018 case BINARY_PRINT_NUM_PAD:
2019 case BINARY_PRINT_SEP:
2020 case BINARY_PRINT_CHAR_PAD:
2021 case BINARY_PRINT_LINE_END:
2022 case BINARY_PRINT_DATA_END:
2023 default:
2024 break;
2025 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002026
2027 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00002028}
2029
2030static void bpf_output__fprintf(struct trace *trace,
2031 struct perf_sample *sample)
2032{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002033 binary__fprintf(sample->raw_data, sample->raw_size, 8,
2034 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00002035}
2036
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002037static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2038 union perf_event *event __maybe_unused,
2039 struct perf_sample *sample)
2040{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002041 int callchain_ret = 0;
2042
2043 if (sample->callchain) {
2044 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2045 if (callchain_ret == 0) {
2046 if (callchain_cursor.nr < trace->min_stack)
2047 goto out;
2048 callchain_ret = 1;
2049 }
2050 }
2051
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03002052 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002053 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002054
2055 if (trace->trace_syscalls)
2056 fprintf(trace->output, "( ): ");
2057
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002058 if (evsel == trace->syscalls.events.augmented) {
2059 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
2060 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2061
2062 if (sc) {
2063 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2064
2065 if (thread) {
2066 fprintf(trace->output, "%s(", sc->name);
2067 trace__fprintf_sys_enter(trace, evsel, sample);
2068 fputc(')', trace->output);
2069 thread__put(thread);
2070 goto newline;
2071 }
2072 }
2073
2074 /*
2075 * XXX: Not having the associated syscall info or not finding/adding
2076 * the thread should never happen, but if it does...
2077 * fall thru and print it as a bpf_output event.
2078 */
2079 }
2080
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002081 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002082
Wang Nan1d6c9402016-02-26 09:31:55 +00002083 if (perf_evsel__is_bpf_output(evsel)) {
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002084 bpf_output__fprintf(trace, sample);
Wang Nan1d6c9402016-02-26 09:31:55 +00002085 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002086 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2087 trace__fprintf_sys_enter(trace, evsel, sample)) {
2088 event_format__fprintf(evsel->tp_format, sample->cpu,
2089 sample->raw_data, sample->raw_size,
2090 trace->output);
2091 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002092 }
2093
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002094newline:
Changbin Du51125a22018-03-13 18:40:01 +08002095 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002096
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002097 if (callchain_ret > 0)
2098 trace__fprintf_callchain(trace, sample);
2099 else if (callchain_ret < 0)
2100 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2101out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002102 return 0;
2103}
2104
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002105static void print_location(FILE *f, struct perf_sample *sample,
2106 struct addr_location *al,
2107 bool print_dso, bool print_sym)
2108{
2109
Namhyung Kimbb963e12017-02-17 17:17:38 +09002110 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002111 fprintf(f, "%s@", al->map->dso->long_name);
2112
Namhyung Kimbb963e12017-02-17 17:17:38 +09002113 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002114 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002115 al->addr - al->sym->start);
2116 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002117 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002118 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002119 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002120}
2121
2122static int trace__pgfault(struct trace *trace,
2123 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002124 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002125 struct perf_sample *sample)
2126{
2127 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002128 struct addr_location al;
2129 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002130 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002131 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002132 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002133
2134 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002135
2136 if (sample->callchain) {
2137 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2138 if (callchain_ret == 0) {
2139 if (callchain_cursor.nr < trace->min_stack)
2140 goto out_put;
2141 callchain_ret = 1;
2142 }
2143 }
2144
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002145 ttrace = thread__trace(thread, trace->output);
2146 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002147 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002148
2149 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2150 ttrace->pfmaj++;
2151 else
2152 ttrace->pfmin++;
2153
2154 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002155 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002156
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002157 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002158
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002159 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002160
2161 fprintf(trace->output, "%sfault [",
2162 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2163 "maj" : "min");
2164
2165 print_location(trace->output, sample, &al, false, true);
2166
2167 fprintf(trace->output, "] => ");
2168
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002169 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002170
2171 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002172 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002173
2174 if (al.map)
2175 map_type = 'x';
2176 else
2177 map_type = '?';
2178 }
2179
2180 print_location(trace->output, sample, &al, true, false);
2181
2182 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002183
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002184 if (callchain_ret > 0)
2185 trace__fprintf_callchain(trace, sample);
2186 else if (callchain_ret < 0)
2187 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002188out:
2189 err = 0;
2190out_put:
2191 thread__put(thread);
2192 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002193}
2194
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002195static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002196 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002197 struct perf_sample *sample)
2198{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002199 /*
2200 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2201 * and don't use sample->time unconditionally, we may end up having
2202 * some other event in the future without PERF_SAMPLE_TIME for good
2203 * reason, i.e. we may not be interested in its timestamps, just in
2204 * it taking place, picking some piece of information when it
2205 * appears in our event stream (vfs_getname comes to mind).
2206 */
2207 if (trace->base_time == 0 && !trace->full_time &&
2208 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002209 trace->base_time = sample->time;
2210}
2211
David Ahern6810fc92013-08-28 22:29:52 -06002212static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002213 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002214 struct perf_sample *sample,
2215 struct perf_evsel *evsel,
2216 struct machine *machine __maybe_unused)
2217{
2218 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002219 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002220 int err = 0;
2221
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002222 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002223
David Ahernaa07df62016-11-25 09:29:52 -07002224 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2225 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002226 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002227
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002228 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002229
David Ahern31605652013-12-04 19:41:41 -07002230 if (handler) {
2231 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002232 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002233 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002234out:
2235 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002236 return err;
2237}
2238
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002239static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002240{
2241 unsigned int rec_argc, i, j;
2242 const char **rec_argv;
2243 const char * const record_args[] = {
2244 "record",
2245 "-R",
2246 "-m", "1024",
2247 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002248 };
2249
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002250 const char * const sc_args[] = { "-e", };
2251 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2252 const char * const majpf_args[] = { "-e", "major-faults" };
2253 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2254 const char * const minpf_args[] = { "-e", "minor-faults" };
2255 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2256
David Ahern9aca7f12013-12-04 19:41:39 -07002257 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002258 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2259 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002260 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2261
2262 if (rec_argv == NULL)
2263 return -ENOMEM;
2264
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002265 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002266 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002267 rec_argv[j++] = record_args[i];
2268
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002269 if (trace->trace_syscalls) {
2270 for (i = 0; i < sc_args_nr; i++)
2271 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002272
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002273 /* event string may be different for older kernels - e.g., RHEL6 */
2274 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2275 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2276 else if (is_valid_tracepoint("syscalls:sys_enter"))
2277 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2278 else {
2279 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002280 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002281 return -1;
2282 }
David Ahern9aca7f12013-12-04 19:41:39 -07002283 }
David Ahern9aca7f12013-12-04 19:41:39 -07002284
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002285 if (trace->trace_pgfaults & TRACE_PFMAJ)
2286 for (i = 0; i < majpf_args_nr; i++)
2287 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002288
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002289 if (trace->trace_pgfaults & TRACE_PFMIN)
2290 for (i = 0; i < minpf_args_nr; i++)
2291 rec_argv[j++] = minpf_args[i];
2292
2293 for (i = 0; i < (unsigned int)argc; i++)
2294 rec_argv[j++] = argv[i];
2295
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002296 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002297}
2298
David Ahernbf2575c2013-10-08 21:26:53 -06002299static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2300
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002301static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002302{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002303 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002304
2305 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002306 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002307
2308 if (perf_evsel__field(evsel, "pathname") == NULL) {
2309 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002310 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002311 }
2312
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002313 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002314 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002315 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002316}
2317
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002318static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002319{
2320 struct perf_evsel *evsel;
2321 struct perf_event_attr attr = {
2322 .type = PERF_TYPE_SOFTWARE,
2323 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002324 };
2325
2326 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002327 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002328
2329 event_attr_init(&attr);
2330
2331 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002332 if (evsel)
2333 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002334
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002335 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002336}
2337
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002338static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2339{
2340 const u32 type = event->header.type;
2341 struct perf_evsel *evsel;
2342
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002343 if (type != PERF_RECORD_SAMPLE) {
2344 trace__process_event(trace, trace->host, event, sample);
2345 return;
2346 }
2347
2348 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2349 if (evsel == NULL) {
2350 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2351 return;
2352 }
2353
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002354 trace__set_base_time(trace, evsel, sample);
2355
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002356 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2357 sample->raw_data == NULL) {
2358 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2359 perf_evsel__name(evsel), sample->tid,
2360 sample->cpu, sample->raw_size);
2361 } else {
2362 tracepoint_handler handler = evsel->handler;
2363 handler(trace, evsel, event, sample);
2364 }
2365}
2366
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002367static int trace__add_syscall_newtp(struct trace *trace)
2368{
2369 int ret = -1;
2370 struct perf_evlist *evlist = trace->evlist;
2371 struct perf_evsel *sys_enter, *sys_exit;
2372
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002373 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002374 if (sys_enter == NULL)
2375 goto out;
2376
2377 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2378 goto out_delete_sys_enter;
2379
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002380 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002381 if (sys_exit == NULL)
2382 goto out_delete_sys_enter;
2383
2384 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2385 goto out_delete_sys_exit;
2386
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002387 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2388 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2389
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002390 perf_evlist__add(evlist, sys_enter);
2391 perf_evlist__add(evlist, sys_exit);
2392
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002393 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002394 /*
2395 * We're interested only in the user space callchain
2396 * leading to the syscall, allow overriding that for
2397 * debugging reasons using --kernel_syscall_callchains
2398 */
2399 sys_exit->attr.exclude_callchain_kernel = 1;
2400 }
2401
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002402 trace->syscalls.events.sys_enter = sys_enter;
2403 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002404
2405 ret = 0;
2406out:
2407 return ret;
2408
2409out_delete_sys_exit:
2410 perf_evsel__delete_priv(sys_exit);
2411out_delete_sys_enter:
2412 perf_evsel__delete_priv(sys_enter);
2413 goto out;
2414}
2415
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002416static int trace__set_ev_qualifier_filter(struct trace *trace)
2417{
2418 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002419 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002420 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2421 trace->ev_qualifier_ids.nr,
2422 trace->ev_qualifier_ids.entries);
2423
2424 if (filter == NULL)
2425 goto out_enomem;
2426
Mathieu Poirier3541c032016-09-16 08:44:04 -06002427 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2428 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002429 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002430 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002431 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002432
2433 free(filter);
2434out:
2435 return err;
2436out_enomem:
2437 errno = ENOMEM;
2438 goto out;
2439}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002440
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002441static int trace__set_filter_loop_pids(struct trace *trace)
2442{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002443 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002444 pid_t pids[32] = {
2445 getpid(),
2446 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002447 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2448
2449 while (thread && nr < ARRAY_SIZE(pids)) {
2450 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2451
2452 if (parent == NULL)
2453 break;
2454
2455 if (!strcmp(thread__comm_str(parent), "sshd")) {
2456 pids[nr++] = parent->tid;
2457 break;
2458 }
2459 thread = parent;
2460 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002461
2462 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2463}
2464
Namhyung Kimf15eb532012-10-05 14:02:16 +09002465static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002466{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002467 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002468 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002469 int err = -1, i;
2470 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002471 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002472 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002473
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002474 trace->live = true;
2475
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002476 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002477 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002478
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002479 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002480 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002481
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002482 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2483 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2484 if (pgfault_maj == NULL)
2485 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002486 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002487 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002488 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002489
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002490 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2491 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2492 if (pgfault_min == NULL)
2493 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002494 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002495 perf_evlist__add(evlist, pgfault_min);
2496 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002497
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002498 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002499 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2500 trace__sched_stat_runtime))
2501 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002502
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002503 /*
2504 * If a global cgroup was set, apply it to all the events without an
2505 * explicit cgroup. I.e.:
2506 *
2507 * trace -G A -e sched:*switch
2508 *
2509 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2510 * _and_ sched:sched_switch to the 'A' cgroup, while:
2511 *
2512 * trace -e sched:*switch -G A
2513 *
2514 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2515 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2516 * a cgroup (on the root cgroup, sys wide, etc).
2517 *
2518 * Multiple cgroups:
2519 *
2520 * trace -G A -e sched:*switch -G B
2521 *
2522 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2523 * to the 'B' cgroup.
2524 *
2525 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2526 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2527 */
2528 if (trace->cgroup)
2529 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2530
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002531 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2532 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002533 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002534 goto out_delete_evlist;
2535 }
2536
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002537 err = trace__symbols_init(trace, evlist);
2538 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002539 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002540 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002541 }
2542
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002543 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002544
Namhyung Kimf15eb532012-10-05 14:02:16 +09002545 signal(SIGCHLD, sig_handler);
2546 signal(SIGINT, sig_handler);
2547
2548 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002549 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002550 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002551 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002552 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002553 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002554 }
2555 }
2556
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002557 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002558 if (err < 0)
2559 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002560
Wang Nanba504232016-02-26 09:31:54 +00002561 err = bpf__apply_obj_config();
2562 if (err) {
2563 char errbuf[BUFSIZ];
2564
2565 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2566 pr_err("ERROR: Apply config to BPF failed: %s\n",
2567 errbuf);
2568 goto out_error_open;
2569 }
2570
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002571 /*
2572 * Better not use !target__has_task() here because we need to cover the
2573 * case where no threads were specified in the command line, but a
2574 * workload was, and in that case we will fill in the thread_map when
2575 * we fork the workload in perf_evlist__prepare_workload.
2576 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002577 if (trace->filter_pids.nr > 0)
2578 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002579 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002580 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002581
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002582 if (err < 0)
2583 goto out_error_mem;
2584
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002585 if (trace->ev_qualifier_ids.nr > 0) {
2586 err = trace__set_ev_qualifier_filter(trace);
2587 if (err < 0)
2588 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002589
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002590 pr_debug("event qualifier tracepoint filter: %s\n",
2591 trace->syscalls.events.sys_exit->filter);
2592 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002593
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002594 err = perf_evlist__apply_filters(evlist, &evsel);
2595 if (err < 0)
2596 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002597
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002598 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002599 if (err < 0)
2600 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002601
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002602 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002603 perf_evlist__enable(evlist);
2604
Namhyung Kimf15eb532012-10-05 14:02:16 +09002605 if (forks)
2606 perf_evlist__start_workload(evlist);
2607
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002608 if (trace->opts.initial_delay) {
2609 usleep(trace->opts.initial_delay * 1000);
2610 perf_evlist__enable(evlist);
2611 }
2612
Jiri Olsae13798c2015-06-23 00:36:02 +02002613 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002614 evlist->threads->nr > 1 ||
2615 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002616
2617 /*
2618 * Now that we already used evsel->attr to ask the kernel to setup the
2619 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2620 * trace__resolve_callchain(), allowing per-event max-stack settings
2621 * to override an explicitely set --max-stack global setting.
2622 */
2623 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002624 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002625 evsel->attr.sample_max_stack == 0)
2626 evsel->attr.sample_max_stack = trace->max_stack;
2627 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002628again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002629 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002630
2631 for (i = 0; i < evlist->nr_mmaps; i++) {
2632 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002633 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002634
Kan Liangd7f55c62018-03-01 18:08:59 -05002635 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002636 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002637 continue;
2638
Kan Liang0019dc872018-03-06 10:36:06 -05002639 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002640 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002641
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002642 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002643
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002644 err = perf_evlist__parse_sample(evlist, event, &sample);
2645 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002646 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002647 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002648 }
2649
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002650 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002651next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002652 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002653
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002654 if (interrupted)
2655 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002656
2657 if (done && !draining) {
2658 perf_evlist__disable(evlist);
2659 draining = true;
2660 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002661 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002662 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002663 }
2664
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002665 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002666 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002667
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002668 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2669 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2670 draining = true;
2671
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002672 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002673 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002674 } else {
2675 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002676 }
2677
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002678out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002679 thread__zput(trace->current);
2680
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002681 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002682
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002683 if (!err) {
2684 if (trace->summary)
2685 trace__fprintf_thread_summary(trace, trace->output);
2686
2687 if (trace->show_tool_stats) {
2688 fprintf(trace->output, "Stats:\n "
2689 " vfs_getname : %" PRIu64 "\n"
2690 " proc_getname: %" PRIu64 "\n",
2691 trace->stats.vfs_getname,
2692 trace->stats.proc_getname);
2693 }
2694 }
David Ahernbf2575c2013-10-08 21:26:53 -06002695
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002696out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002697 trace__symbols__exit(trace);
2698
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002699 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002700 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002701 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002702 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002703 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002704{
2705 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002706
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002707out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002708 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002709 goto out_error;
2710
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002711out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002712 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002713 goto out_error;
2714
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002715out_error_mmap:
2716 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2717 goto out_error;
2718
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002719out_error_open:
2720 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2721
2722out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002723 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302724 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002725
2726out_error_apply_filters:
2727 fprintf(trace->output,
2728 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2729 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002730 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002731 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002732}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002733out_error_mem:
2734 fprintf(trace->output, "Not enough memory to run!\n");
2735 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002736
2737out_errno:
2738 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2739 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002740}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002741
David Ahern6810fc92013-08-28 22:29:52 -06002742static int trace__replay(struct trace *trace)
2743{
2744 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002745 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002746 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002747 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002748 .file = {
2749 .path = input_name,
2750 },
2751 .mode = PERF_DATA_MODE_READ,
2752 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002753 };
David Ahern6810fc92013-08-28 22:29:52 -06002754 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002755 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002756 int err = -1;
2757
2758 trace->tool.sample = trace__process_sample;
2759 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002760 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002761 trace->tool.comm = perf_event__process_comm;
2762 trace->tool.exit = perf_event__process_exit;
2763 trace->tool.fork = perf_event__process_fork;
2764 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302765 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002766 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302767 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002768
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002769 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002770 trace->tool.ordering_requires_timestamps = true;
2771
2772 /* add tid to output */
2773 trace->multiple_threads = true;
2774
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002775 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002776 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002777 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002778
David Ahernaa07df62016-11-25 09:29:52 -07002779 if (trace->opts.target.pid)
2780 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2781
2782 if (trace->opts.target.tid)
2783 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2784
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002785 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002786 goto out;
2787
David Ahern8fb598e2013-09-28 13:13:00 -06002788 trace->host = &session->machines.host;
2789
David Ahern6810fc92013-08-28 22:29:52 -06002790 err = perf_session__set_tracepoints_handlers(session, handlers);
2791 if (err)
2792 goto out;
2793
Namhyung Kim003824e2013-11-12 15:25:00 +09002794 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2795 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002796 /* older kernels have syscalls tp versus raw_syscalls */
2797 if (evsel == NULL)
2798 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2799 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002800
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002801 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002802 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002803 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002804 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2805 goto out;
2806 }
2807
2808 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2809 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002810 if (evsel == NULL)
2811 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2812 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002813 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002814 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002815 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002816 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002817 goto out;
2818 }
2819
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002820 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002821 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2822 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2823 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2824 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2825 evsel->handler = trace__pgfault;
2826 }
2827
David Ahern6810fc92013-08-28 22:29:52 -06002828 setup_pager();
2829
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002830 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002831 if (err)
2832 pr_err("Failed to process events, error %d", err);
2833
David Ahernbf2575c2013-10-08 21:26:53 -06002834 else if (trace->summary)
2835 trace__fprintf_thread_summary(trace, trace->output);
2836
David Ahern6810fc92013-08-28 22:29:52 -06002837out:
2838 perf_session__delete(session);
2839
2840 return err;
2841}
2842
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002843static size_t trace__fprintf_threads_header(FILE *fp)
2844{
2845 size_t printed;
2846
Pekka Enberg99ff7152013-11-12 16:42:14 +02002847 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002848
2849 return printed;
2850}
2851
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002852DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2853 struct stats *stats;
2854 double msecs;
2855 int syscall;
2856)
2857{
2858 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2859 struct stats *stats = source->priv;
2860
2861 entry->syscall = source->i;
2862 entry->stats = stats;
2863 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2864}
2865
David Ahernbf2575c2013-10-08 21:26:53 -06002866static size_t thread__dump_stats(struct thread_trace *ttrace,
2867 struct trace *trace, FILE *fp)
2868{
David Ahernbf2575c2013-10-08 21:26:53 -06002869 size_t printed = 0;
2870 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002871 struct rb_node *nd;
2872 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002873
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002874 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002875 return 0;
2876
2877 printed += fprintf(fp, "\n");
2878
Milian Wolff834fd462015-08-06 11:24:29 +02002879 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2880 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2881 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002882
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002883 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002884 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002885 if (stats) {
2886 double min = (double)(stats->min) / NSEC_PER_MSEC;
2887 double max = (double)(stats->max) / NSEC_PER_MSEC;
2888 double avg = avg_stats(stats);
2889 double pct;
2890 u64 n = (u64) stats->n;
2891
2892 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2893 avg /= NSEC_PER_MSEC;
2894
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002895 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002896 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002897 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002898 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002899 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002900 }
David Ahernbf2575c2013-10-08 21:26:53 -06002901 }
2902
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002903 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002904 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002905
2906 return printed;
2907}
2908
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002909static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002910{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002911 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002912 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002913 double ratio;
2914
2915 if (ttrace == NULL)
2916 return 0;
2917
2918 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2919
Pekka Enberg15e65c62013-11-14 18:43:30 +02002920 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002921 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002922 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002923 if (ttrace->pfmaj)
2924 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2925 if (ttrace->pfmin)
2926 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002927 if (trace->sched)
2928 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2929 else if (fputc('\n', fp) != EOF)
2930 ++printed;
2931
David Ahernbf2575c2013-10-08 21:26:53 -06002932 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002933
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002934 return printed;
2935}
David Ahern896cbb52013-09-28 13:12:59 -06002936
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002937static unsigned long thread__nr_events(struct thread_trace *ttrace)
2938{
2939 return ttrace ? ttrace->nr_events : 0;
2940}
2941
2942DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2943 struct thread *thread;
2944)
2945{
2946 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002947}
2948
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002949static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2950{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002951 size_t printed = trace__fprintf_threads_header(fp);
2952 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002953 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002954
Kan Liang91e467b2017-09-10 19:23:14 -07002955 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2956 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2957
2958 if (threads == NULL) {
2959 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2960 return 0;
2961 }
2962
2963 resort_rb__for_each_entry(nd, threads)
2964 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2965
2966 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002967 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002968 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002969}
2970
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002971static int trace__set_duration(const struct option *opt, const char *str,
2972 int unset __maybe_unused)
2973{
2974 struct trace *trace = opt->value;
2975
2976 trace->duration_filter = atof(str);
2977 return 0;
2978}
2979
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002980static int trace__set_filter_pids(const struct option *opt, const char *str,
2981 int unset __maybe_unused)
2982{
2983 int ret = -1;
2984 size_t i;
2985 struct trace *trace = opt->value;
2986 /*
2987 * FIXME: introduce a intarray class, plain parse csv and create a
2988 * { int nr, int entries[] } struct...
2989 */
2990 struct intlist *list = intlist__new(str);
2991
2992 if (list == NULL)
2993 return -1;
2994
2995 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2996 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2997
2998 if (trace->filter_pids.entries == NULL)
2999 goto out;
3000
3001 trace->filter_pids.entries[0] = getpid();
3002
3003 for (i = 1; i < trace->filter_pids.nr; ++i)
3004 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3005
3006 intlist__delete(list);
3007 ret = 0;
3008out:
3009 return ret;
3010}
3011
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003012static int trace__open_output(struct trace *trace, const char *filename)
3013{
3014 struct stat st;
3015
3016 if (!stat(filename, &st) && st.st_size) {
3017 char oldname[PATH_MAX];
3018
3019 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3020 unlink(oldname);
3021 rename(filename, oldname);
3022 }
3023
3024 trace->output = fopen(filename, "w");
3025
3026 return trace->output == NULL ? -errno : 0;
3027}
3028
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003029static int parse_pagefaults(const struct option *opt, const char *str,
3030 int unset __maybe_unused)
3031{
3032 int *trace_pgfaults = opt->value;
3033
3034 if (strcmp(str, "all") == 0)
3035 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3036 else if (strcmp(str, "maj") == 0)
3037 *trace_pgfaults |= TRACE_PFMAJ;
3038 else if (strcmp(str, "min") == 0)
3039 *trace_pgfaults |= TRACE_PFMIN;
3040 else
3041 return -1;
3042
3043 return 0;
3044}
3045
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003046static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3047{
3048 struct perf_evsel *evsel;
3049
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003050 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003051 evsel->handler = handler;
3052}
3053
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003054static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist)
3055{
3056 struct perf_evsel *evsel;
3057
3058 evlist__for_each_entry(evlist, evsel) {
3059 if (evsel->priv || !evsel->tp_format)
3060 continue;
3061
3062 if (strcmp(evsel->tp_format->system, "syscalls"))
3063 continue;
3064
3065 if (perf_evsel__init_syscall_tp(evsel))
3066 return -1;
3067
3068 if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
3069 struct syscall_tp *sc = evsel->priv;
3070
3071 if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
3072 return -1;
3073 } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
3074 struct syscall_tp *sc = evsel->priv;
3075
3076 if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
3077 return -1;
3078 }
3079 }
3080
3081 return 0;
3082}
3083
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003084/*
3085 * XXX: Hackish, just splitting the combined -e+--event (syscalls
3086 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
3087 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
3088 *
3089 * It'd be better to introduce a parse_options() variant that would return a
3090 * list with the terms it didn't match to an event...
3091 */
3092static int trace__parse_events_option(const struct option *opt, const char *str,
3093 int unset __maybe_unused)
3094{
3095 struct trace *trace = (struct trace *)opt->value;
3096 const char *s = str;
3097 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003098 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003099 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
3100 char group_name[PATH_MAX];
3101
3102 if (strace_groups_dir == NULL)
3103 return -1;
3104
3105 if (*s == '!') {
3106 ++s;
3107 trace->not_ev_qualifier = true;
3108 }
3109
3110 while (1) {
3111 if ((sep = strchr(s, ',')) != NULL)
3112 *sep = '\0';
3113
3114 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003115 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3116 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003117 list = 1;
3118 } else {
3119 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3120 if (access(group_name, R_OK) == 0)
3121 list = 1;
3122 }
3123
3124 if (lists[list]) {
3125 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3126 } else {
3127 lists[list] = malloc(len);
3128 if (lists[list] == NULL)
3129 goto out;
3130 strcpy(lists[list], s);
3131 }
3132
3133 if (!sep)
3134 break;
3135
3136 *sep = ',';
3137 s = sep + 1;
3138 }
3139
3140 if (lists[1] != NULL) {
3141 struct strlist_config slist_config = {
3142 .dirname = strace_groups_dir,
3143 };
3144
3145 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3146 if (trace->ev_qualifier == NULL) {
3147 fputs("Not enough memory to parse event qualifier", trace->output);
3148 goto out;
3149 }
3150
3151 if (trace__validate_ev_qualifier(trace))
3152 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003153 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003154 }
3155
3156 err = 0;
3157
3158 if (lists[0]) {
3159 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3160 "event selector. use 'perf list' to list available events",
3161 parse_events_option);
3162 err = parse_events_option(&o, lists[0], 0);
3163 }
3164out:
3165 if (sep)
3166 *sep = ',';
3167
3168 return err;
3169}
3170
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003171static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3172{
3173 struct trace *trace = opt->value;
3174
3175 if (!list_empty(&trace->evlist->entries))
3176 return parse_cgroups(opt, str, unset);
3177
3178 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3179
3180 return 0;
3181}
3182
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003183int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003184{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003185 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003186 "perf trace [<options>] [<command>]",
3187 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003188 "perf trace record [<options>] [<command>]",
3189 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003190 NULL
3191 };
3192 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003193 .syscalls = {
3194 . max = -1,
3195 },
3196 .opts = {
3197 .target = {
3198 .uid = UINT_MAX,
3199 .uses_mmap = true,
3200 },
3201 .user_freq = UINT_MAX,
3202 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003203 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003204 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003205 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003206 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003207 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003208 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003209 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003210 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003211 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003212 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003213 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003214 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003215 OPT_CALLBACK('e', "event", &trace, "event",
3216 "event/syscall selector. use 'perf list' to list available events",
3217 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003218 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3219 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003220 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003221 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3222 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003223 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003224 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003225 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3226 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003227 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003228 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003229 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3230 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003231 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003232 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003233 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003234 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003235 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003236 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003237 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3238 "number of mmap data pages",
3239 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003240 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003241 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003242 OPT_CALLBACK(0, "duration", &trace, "float",
3243 "show only events with duration > N.M ms",
3244 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003245 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003246 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003247 OPT_BOOLEAN('T', "time", &trace.full_time,
3248 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003249 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3250 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003251 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3252 "Show only syscall summary with statistics"),
3253 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3254 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003255 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3256 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003257 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003258 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003259 OPT_CALLBACK(0, "call-graph", &trace.opts,
3260 "record_mode[,record_size]", record_callchain_help,
3261 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003262 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3263 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003264 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3265 "Set the minimum stack depth when parsing the callchain, "
3266 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003267 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3268 "Set the maximum stack depth when parsing the callchain, "
3269 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003270 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003271 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3272 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003273 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3274 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003275 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3276 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003277 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3278 "ms to wait before starting measurement after program "
3279 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003280 OPT_END()
3281 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003282 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003283 bool mmap_pages_user_set = true;
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003284 struct perf_evsel *evsel;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003285 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003286 int err = -1;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003287 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003288
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003289 signal(SIGSEGV, sighandler_dump_stack);
3290 signal(SIGFPE, sighandler_dump_stack);
3291
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003292 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003293 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003294
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003295 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003296 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003297 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003298 goto out;
3299 }
3300
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003301 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3302 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003303
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003304 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3305 usage_with_options_msg(trace_usage, trace_options,
3306 "cgroup monitoring only available in system-wide mode");
3307 }
3308
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003309 evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__");
3310 if (IS_ERR(evsel)) {
3311 bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf));
Arnaldo Carvalho de Meloe0b6d2e2018-08-07 15:40:13 -03003312 pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf);
3313 goto out;
3314 }
3315
Arnaldo Carvalho de Melod3d1c4bdf52018-08-07 16:21:44 -03003316 if (evsel) {
3317 if (perf_evsel__init_augmented_syscall_tp(evsel) ||
3318 perf_evsel__init_augmented_syscall_tp_args(evsel))
3319 goto out;
3320 trace.syscalls.events.augmented = evsel;
3321 }
3322
Wang Nand7888572016-04-08 15:07:24 +00003323 err = bpf__setup_stdout(trace.evlist);
3324 if (err) {
3325 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3326 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3327 goto out;
3328 }
3329
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003330 err = -1;
3331
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003332 if (trace.trace_pgfaults) {
3333 trace.opts.sample_address = true;
3334 trace.opts.sample_time = true;
3335 }
3336
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003337 if (trace.opts.mmap_pages == UINT_MAX)
3338 mmap_pages_user_set = false;
3339
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003340 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003341 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003342 max_stack_user_set = false;
3343 }
3344
3345#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003346 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003347 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003348 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003349#endif
3350
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003351 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003352 if (!mmap_pages_user_set && geteuid() == 0)
3353 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3354
Milian Wolff566a0882016-04-08 13:34:15 +02003355 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003356 }
Milian Wolff566a0882016-04-08 13:34:15 +02003357
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003358 if (trace.evlist->nr_entries > 0) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003359 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003360 if (evlist__set_syscall_tp_fields(trace.evlist)) {
3361 perror("failed to set syscalls:* tracepoint fields");
3362 goto out;
3363 }
3364 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003365
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003366 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3367 return trace__record(&trace, argc-1, &argv[1]);
3368
3369 /* summary_only implies summary option, but don't overwrite summary if set */
3370 if (trace.summary_only)
3371 trace.summary = trace.summary_only;
3372
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003373 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3374 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003375 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003376 }
3377
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003378 if (output_name != NULL) {
3379 err = trace__open_output(&trace, output_name);
3380 if (err < 0) {
3381 perror("failed to create output file");
3382 goto out;
3383 }
3384 }
3385
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003386 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003387 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003388 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003389 fprintf(trace.output, "%s", bf);
3390 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003391 }
3392
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003393 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003394 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003395 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003396 fprintf(trace.output, "%s", bf);
3397 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003398 }
3399
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003400 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003401 trace.opts.target.system_wide = true;
3402
David Ahern6810fc92013-08-28 22:29:52 -06003403 if (input_name)
3404 err = trace__replay(&trace);
3405 else
3406 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003407
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003408out_close:
3409 if (output_name != NULL)
3410 fclose(trace.output);
3411out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003412 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003413}