blob: e46ac90091724db6c3e3607998247276fce95177 [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 Melo6dcbd212018-08-21 11:40:09 -03001147static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148{
Arnaldo Carvalho de Melo6dcbd212018-08-21 11:40:09 -03001149 size_t printed = 0;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001150
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001151 if (trace->multiple_threads) {
1152 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001153 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001154 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001155 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001156
1157 return printed;
1158}
1159
Arnaldo Carvalho de Melo6dcbd212018-08-21 11:40:09 -03001160static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
1161 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
1162{
1163 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
1164 printed += fprintf_duration(duration, duration_calculated, fp);
1165 return printed + trace__fprintf_comm_tid(trace, thread, fp);
1166}
1167
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001168static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001169 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001170{
1171 int ret = 0;
1172
1173 switch (event->header.type) {
1174 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001175 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001176 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001177 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001178 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001179 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001180 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001181 break;
1182 }
1183
1184 return ret;
1185}
1186
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001187static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001188 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001189 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001190 struct machine *machine)
1191{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001192 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001193 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001194}
1195
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001196static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1197{
1198 struct machine *machine = vmachine;
1199
1200 if (machine->kptr_restrict_warned)
1201 return NULL;
1202
1203 if (symbol_conf.kptr_restrict) {
1204 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1205 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1206 "Kernel samples will not be resolved.\n");
1207 machine->kptr_restrict_warned = true;
1208 return NULL;
1209 }
1210
1211 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1212}
1213
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001214static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1215{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001216 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001217
1218 if (err)
1219 return err;
1220
David Ahern8fb598e2013-09-28 13:13:00 -06001221 trace->host = machine__new_host();
1222 if (trace->host == NULL)
1223 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001224
Andrei Vagincbd5c172017-11-07 16:22:46 -08001225 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1226 if (err < 0)
1227 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001228
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001229 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001230 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001231 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001232out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001233 if (err)
1234 symbol__exit();
1235
1236 return err;
1237}
1238
Andrei Vagin33974a42017-11-07 16:22:45 -08001239static void trace__symbols__exit(struct trace *trace)
1240{
1241 machine__exit(trace->host);
1242 trace->host = NULL;
1243
1244 symbol__exit();
1245}
1246
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001247static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1248{
1249 int idx;
1250
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001251 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1252 nr_args = sc->fmt->nr_args;
1253
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001254 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1255 if (sc->arg_fmt == NULL)
1256 return -1;
1257
1258 for (idx = 0; idx < nr_args; ++idx) {
1259 if (sc->fmt)
1260 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1261 }
1262
1263 sc->nr_args = nr_args;
1264 return 0;
1265}
1266
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001267static int syscall__set_arg_fmts(struct syscall *sc)
1268{
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001269 struct format_field *field, *last_field = NULL;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001270 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001271
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001272 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001273 last_field = field;
1274
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001275 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1276 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001277
1278 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001279 (strcmp(field->name, "filename") == 0 ||
1280 strcmp(field->name, "path") == 0 ||
1281 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001282 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001283 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001284 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001285 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001286 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001287 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001288 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001289 else if ((strcmp(field->type, "int") == 0 ||
1290 strcmp(field->type, "unsigned int") == 0 ||
1291 strcmp(field->type, "long") == 0) &&
1292 (len = strlen(field->name)) >= 2 &&
1293 strcmp(field->name + len - 2, "fd") == 0) {
1294 /*
1295 * /sys/kernel/tracing/events/syscalls/sys_enter*
1296 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1297 * 65 int
1298 * 23 unsigned int
1299 * 7 unsigned long
1300 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001301 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001302 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001303 }
1304
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001305 if (last_field)
1306 sc->args_size = last_field->offset + last_field->size;
1307
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001308 return 0;
1309}
1310
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001311static int trace__read_syscall_info(struct trace *trace, int id)
1312{
1313 char tp_name[128];
1314 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001315 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001316
1317 if (name == NULL)
1318 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001319
1320 if (id > trace->syscalls.max) {
1321 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1322
1323 if (nsyscalls == NULL)
1324 return -1;
1325
1326 if (trace->syscalls.max != -1) {
1327 memset(nsyscalls + trace->syscalls.max + 1, 0,
1328 (id - trace->syscalls.max) * sizeof(*sc));
1329 } else {
1330 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1331 }
1332
1333 trace->syscalls.table = nsyscalls;
1334 trace->syscalls.max = id;
1335 }
1336
1337 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001338 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001339
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001340 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001341
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001342 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001343 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001344
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001345 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001346 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001347 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001348 }
1349
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001350 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1351 return -1;
1352
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001353 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001354 return -1;
1355
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001356 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001357 /*
1358 * We need to check and discard the first variable '__syscall_nr'
1359 * or 'nr' that mean the syscall number. It is needless here.
1360 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1361 */
1362 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001363 sc->args = sc->args->next;
1364 --sc->nr_args;
1365 }
1366
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001367 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001368 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001369
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001370 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001371}
1372
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001373static int trace__validate_ev_qualifier(struct trace *trace)
1374{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001375 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001376 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001377 struct str_node *pos;
1378
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001379 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1380 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1381 sizeof(trace->ev_qualifier_ids.entries[0]));
1382
1383 if (trace->ev_qualifier_ids.entries == NULL) {
1384 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1385 trace->output);
1386 err = -EINVAL;
1387 goto out;
1388 }
1389
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001390 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001391 i = 0;
1392
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001393 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001394 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001395 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001396
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001397 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001398 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1399 if (id >= 0)
1400 goto matches;
1401
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001402 if (err == 0) {
1403 fputs("Error:\tInvalid syscall ", trace->output);
1404 err = -EINVAL;
1405 } else {
1406 fputs(", ", trace->output);
1407 }
1408
1409 fputs(sc, trace->output);
1410 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001411matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001412 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001413 if (match_next == -1)
1414 continue;
1415
1416 while (1) {
1417 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1418 if (id < 0)
1419 break;
1420 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1421 void *entries;
1422
1423 nr_allocated += 8;
1424 entries = realloc(trace->ev_qualifier_ids.entries,
1425 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1426 if (entries == NULL) {
1427 err = -ENOMEM;
1428 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1429 goto out_free;
1430 }
1431 trace->ev_qualifier_ids.entries = entries;
1432 }
1433 trace->ev_qualifier_ids.nr++;
1434 trace->ev_qualifier_ids.entries[i++] = id;
1435 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001436 }
1437
1438 if (err < 0) {
1439 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1440 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001441out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001442 zfree(&trace->ev_qualifier_ids.entries);
1443 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001444 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001445out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001446 return err;
1447}
1448
David Ahern55d43bca2015-02-19 15:00:22 -05001449/*
1450 * args is to be interpreted as a series of longs but we need to handle
1451 * 8-byte unaligned accesses. args points to raw_data within the event
1452 * and raw_data is guaranteed to be 8-byte unaligned because it is
1453 * preceded by raw_size which is a u32. So we need to copy args to a temp
1454 * variable to read it. Most notably this avoids extended load instructions
1455 * on unaligned addresses
1456 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001457unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001458{
1459 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001460 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001461
1462 memcpy(&val, p, sizeof(val));
1463 return val;
1464}
1465
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001466static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1467 struct syscall_arg *arg)
1468{
1469 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1470 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1471
1472 return scnprintf(bf, size, "arg%d: ", arg->idx);
1473}
1474
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001475static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1476 struct syscall_arg *arg, unsigned long val)
1477{
1478 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1479 arg->val = val;
1480 if (sc->arg_fmt[arg->idx].parm)
1481 arg->parm = sc->arg_fmt[arg->idx].parm;
1482 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1483 }
1484 return scnprintf(bf, size, "%ld", val);
1485}
1486
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001487static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001488 unsigned char *args, void *augmented_args, int augmented_args_size,
1489 struct trace *trace, struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001490{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001491 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001492 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001493 u8 bit = 1;
1494 struct syscall_arg arg = {
1495 .args = args,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001496 .augmented = {
1497 .size = augmented_args_size,
1498 .args = augmented_args,
1499 },
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001500 .idx = 0,
1501 .mask = 0,
1502 .trace = trace,
1503 .thread = thread,
1504 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001505 struct thread_trace *ttrace = thread__priv(thread);
1506
1507 /*
1508 * Things like fcntl will set this in its 'cmd' formatter to pick the
1509 * right formatter for the return value (an fd? file flags?), which is
1510 * not needed for syscalls that always return a given type, say an fd.
1511 */
1512 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001513
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001514 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001515 struct format_field *field;
1516
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001517 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001518 field = field->next, ++arg.idx, bit <<= 1) {
1519 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001520 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001521
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001522 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001523
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001524 /*
1525 * Suppress this argument if its value is zero and
1526 * and we don't have a string associated in an
1527 * strarray for it.
1528 */
David Ahern55d43bca2015-02-19 15:00:22 -05001529 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001530 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001531 (sc->arg_fmt[arg.idx].show_zero ||
1532 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001533 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1534 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001535 continue;
1536
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001537 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001538 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001539 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001540 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001541 } else if (IS_ERR(sc->tp_format)) {
1542 /*
1543 * If we managed to read the tracepoint /format file, then we
1544 * may end up not having any args, like with gettid(), so only
1545 * print the raw args when we didn't manage to read it.
1546 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001547 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001548 if (arg.mask & bit)
1549 goto next_arg;
1550 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001551 if (printed)
1552 printed += scnprintf(bf + printed, size - printed, ", ");
1553 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001554 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1555next_arg:
1556 ++arg.idx;
1557 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001558 }
1559 }
1560
1561 return printed;
1562}
1563
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001564typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001565 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001566 struct perf_sample *sample);
1567
1568static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001569 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001570{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001571
1572 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001573
1574 /*
1575 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1576 * before that, leaving at a higher verbosity level till that is
1577 * explained. Reproduced with plain ftrace with:
1578 *
1579 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1580 * grep "NR -1 " /t/trace_pipe
1581 *
1582 * After generating some load on the machine.
1583 */
1584 if (verbose > 1) {
1585 static u64 n;
1586 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1587 id, perf_evsel__name(evsel), ++n);
1588 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001589 return NULL;
1590 }
1591
1592 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1593 trace__read_syscall_info(trace, id))
1594 goto out_cant_read;
1595
1596 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1597 goto out_cant_read;
1598
1599 return &trace->syscalls.table[id];
1600
1601out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001602 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001603 fprintf(trace->output, "Problems reading syscall %d", id);
1604 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1605 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1606 fputs(" information\n", trace->output);
1607 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001608 return NULL;
1609}
1610
David Ahernbf2575c2013-10-08 21:26:53 -06001611static void thread__update_stats(struct thread_trace *ttrace,
1612 int id, struct perf_sample *sample)
1613{
1614 struct int_node *inode;
1615 struct stats *stats;
1616 u64 duration = 0;
1617
1618 inode = intlist__findnew(ttrace->syscall_stats, id);
1619 if (inode == NULL)
1620 return;
1621
1622 stats = inode->priv;
1623 if (stats == NULL) {
1624 stats = malloc(sizeof(struct stats));
1625 if (stats == NULL)
1626 return;
1627 init_stats(stats);
1628 inode->priv = stats;
1629 }
1630
1631 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1632 duration = sample->time - ttrace->entry_time;
1633
1634 update_stats(stats, duration);
1635}
1636
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001637static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001638{
1639 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001640 size_t printed;
1641
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001642 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001643 return 0;
1644
1645 ttrace = thread__priv(trace->current);
1646
1647 if (!ttrace->entry_pending)
1648 return 0;
1649
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001650 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001651 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1652 ttrace->entry_pending = false;
1653
1654 return printed;
1655}
1656
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001657static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1658 struct perf_sample *sample, struct thread *thread)
1659{
1660 int printed = 0;
1661
1662 if (trace->print_sample) {
1663 double ts = (double)sample->time / NSEC_PER_MSEC;
1664
1665 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1666 perf_evsel__name(evsel), ts,
1667 thread__comm_str(thread),
1668 sample->pid, sample->tid, sample->cpu);
1669 }
1670
1671 return printed;
1672}
1673
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001674static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001675 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001676 struct perf_sample *sample)
1677{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001679 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001681 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001682 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001683 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001684 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001685
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001686 if (sc == NULL)
1687 return -1;
1688
David Ahern8fb598e2013-09-28 13:13:00 -06001689 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001690 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001691 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001692 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001693
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001694 trace__fprintf_sample(trace, evsel, sample, thread);
1695
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001696 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001697
1698 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001699 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001700 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001701 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001702 }
1703
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001704 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001705 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001706
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001707 ttrace->entry_time = sample->time;
1708 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001709 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001710
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001711 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001712 args, NULL, 0, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001713
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001714 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001715 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001716 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001717 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001718 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001719 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001720 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001721 /* See trace__vfs_getname & trace__sys_exit */
1722 ttrace->filename.pending_open = false;
1723 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001724
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001725 if (trace->current != thread) {
1726 thread__put(trace->current);
1727 trace->current = thread__get(thread);
1728 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001729 err = 0;
1730out_put:
1731 thread__put(thread);
1732 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001733}
1734
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001735static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1736 struct perf_sample *sample)
1737{
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001738 struct thread_trace *ttrace;
1739 struct thread *thread;
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001740 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
1741 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001742 char msg[1024];
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001743 void *args, *augmented_args = NULL;
1744 int augmented_args_size;
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001745
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001746 if (sc == NULL)
1747 return -1;
1748
1749 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1750 ttrace = thread__trace(thread, trace->output);
1751 /*
1752 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1753 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1754 */
1755 if (ttrace == NULL)
1756 goto out_put;
1757
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001758 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001759 augmented_args_size = sample->raw_size - sc->args_size;
1760 if (augmented_args_size > 0)
1761 augmented_args = sample->raw_data + sc->args_size;
1762
1763 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001764 fprintf(trace->output, "%s", msg);
1765 err = 0;
1766out_put:
1767 thread__put(thread);
1768 return err;
1769}
1770
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001771static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1772 struct perf_sample *sample,
1773 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001774{
1775 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301776 int max_stack = evsel->attr.sample_max_stack ?
1777 evsel->attr.sample_max_stack :
1778 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001779
1780 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301781 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001782 return -1;
1783
1784 return 0;
1785}
1786
1787static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1788{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001789 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001790 const unsigned int print_opts = EVSEL__PRINT_SYM |
1791 EVSEL__PRINT_DSO |
1792 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001793
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001794 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001795}
1796
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001797static const char *errno_to_name(struct perf_evsel *evsel, int err)
1798{
1799 struct perf_env *env = perf_evsel__env(evsel);
1800 const char *arch_name = perf_env__arch(env);
1801
1802 return arch_syscalls__strerrno(arch_name, err);
1803}
1804
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001805static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001806 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001807 struct perf_sample *sample)
1808{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001809 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001810 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001811 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001812 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001813 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001814 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001815 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001816
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001817 if (sc == NULL)
1818 return -1;
1819
David Ahern8fb598e2013-09-28 13:13:00 -06001820 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001821 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001822 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001823 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001824
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001825 trace__fprintf_sample(trace, evsel, sample, thread);
1826
David Ahernbf2575c2013-10-08 21:26:53 -06001827 if (trace->summary)
1828 thread__update_stats(ttrace, id, sample);
1829
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001830 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001831
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001832 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001833 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1834 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001835 ++trace->stats.vfs_getname;
1836 }
1837
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001838 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001839 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001840 if (trace__filter_duration(trace, duration))
1841 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001842 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001843 } else if (trace->duration_filter)
1844 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001845
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001846 if (sample->callchain) {
1847 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1848 if (callchain_ret == 0) {
1849 if (callchain_cursor.nr < trace->min_stack)
1850 goto out;
1851 callchain_ret = 1;
1852 }
1853 }
1854
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001855 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001856 goto out;
1857
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001858 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001859
1860 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001861 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001862 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001863 fprintf(trace->output, " ... [");
1864 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1865 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001866 }
1867
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001868 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001869 if (ret < 0)
1870 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001871signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001872 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001873 } else if (ret < 0) {
1874errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001875 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001876 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001877 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001878
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001879 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001880 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001881 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001882 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001883 else if (ttrace->ret_scnprintf) {
1884 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001885 struct syscall_arg arg = {
1886 .val = ret,
1887 .thread = thread,
1888 .trace = trace,
1889 };
1890 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001891 ttrace->ret_scnprintf = NULL;
1892 fprintf(trace->output, ") = %s", bf);
1893 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001894 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001895 else if (sc->fmt->errpid) {
1896 struct thread *child = machine__find_thread(trace->host, ret, ret);
1897
1898 if (child != NULL) {
1899 fprintf(trace->output, ") = %ld", ret);
1900 if (child->comm_set)
1901 fprintf(trace->output, " (%s)", thread__comm_str(child));
1902 thread__put(child);
1903 }
1904 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001905 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001906
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001907 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001908
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001909 if (callchain_ret > 0)
1910 trace__fprintf_callchain(trace, sample);
1911 else if (callchain_ret < 0)
1912 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001913out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001914 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001915 err = 0;
1916out_put:
1917 thread__put(thread);
1918 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001919}
1920
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001921static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001922 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001923 struct perf_sample *sample)
1924{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001925 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1926 struct thread_trace *ttrace;
1927 size_t filename_len, entry_str_len, to_move;
1928 ssize_t remaining_space;
1929 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001930 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001931
1932 if (!thread)
1933 goto out;
1934
1935 ttrace = thread__priv(thread);
1936 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001937 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001938
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001939 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001940 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001941 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001942
1943 if (ttrace->filename.namelen < filename_len) {
1944 char *f = realloc(ttrace->filename.name, filename_len + 1);
1945
1946 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001947 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001948
1949 ttrace->filename.namelen = filename_len;
1950 ttrace->filename.name = f;
1951 }
1952
1953 strcpy(ttrace->filename.name, filename);
1954 ttrace->filename.pending_open = true;
1955
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001956 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001957 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001958
1959 entry_str_len = strlen(ttrace->entry_str);
1960 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1961 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001962 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001963
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001964 if (filename_len > (size_t)remaining_space) {
1965 filename += filename_len - remaining_space;
1966 filename_len = remaining_space;
1967 }
1968
1969 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1970 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1971 memmove(pos + filename_len, pos, to_move);
1972 memcpy(pos, filename, filename_len);
1973
1974 ttrace->filename.ptr = 0;
1975 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001976out_put:
1977 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001978out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001979 return 0;
1980}
1981
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001982static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001983 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001984 struct perf_sample *sample)
1985{
1986 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1987 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001988 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001989 sample->pid,
1990 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001991 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001992
1993 if (ttrace == NULL)
1994 goto out_dump;
1995
1996 ttrace->runtime_ms += runtime_ms;
1997 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001998out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001999 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002000 return 0;
2001
2002out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002003 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002004 evsel->name,
2005 perf_evsel__strval(evsel, sample, "comm"),
2006 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2007 runtime,
2008 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002009 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002010}
2011
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002012static int bpf_output__printer(enum binary_printer_ops op,
2013 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00002014{
Wang Nan1d6c9402016-02-26 09:31:55 +00002015 unsigned char ch = (unsigned char)val;
2016
2017 switch (op) {
2018 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002019 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00002020 case BINARY_PRINT_DATA_BEGIN:
2021 case BINARY_PRINT_LINE_BEGIN:
2022 case BINARY_PRINT_ADDR:
2023 case BINARY_PRINT_NUM_DATA:
2024 case BINARY_PRINT_NUM_PAD:
2025 case BINARY_PRINT_SEP:
2026 case BINARY_PRINT_CHAR_PAD:
2027 case BINARY_PRINT_LINE_END:
2028 case BINARY_PRINT_DATA_END:
2029 default:
2030 break;
2031 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002032
2033 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00002034}
2035
2036static void bpf_output__fprintf(struct trace *trace,
2037 struct perf_sample *sample)
2038{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002039 binary__fprintf(sample->raw_data, sample->raw_size, 8,
2040 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00002041}
2042
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002043static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2044 union perf_event *event __maybe_unused,
2045 struct perf_sample *sample)
2046{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002047 int callchain_ret = 0;
2048
2049 if (sample->callchain) {
2050 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2051 if (callchain_ret == 0) {
2052 if (callchain_cursor.nr < trace->min_stack)
2053 goto out;
2054 callchain_ret = 1;
2055 }
2056 }
2057
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03002058 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002059 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002060
2061 if (trace->trace_syscalls)
2062 fprintf(trace->output, "( ): ");
2063
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002064 if (evsel == trace->syscalls.events.augmented) {
2065 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
2066 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2067
2068 if (sc) {
2069 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2070
2071 if (thread) {
Arnaldo Carvalho de Meloc96f4ed2018-08-21 11:47:44 -03002072 trace__fprintf_comm_tid(trace, thread, trace->output);
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002073 fprintf(trace->output, "%s(", sc->name);
2074 trace__fprintf_sys_enter(trace, evsel, sample);
2075 fputc(')', trace->output);
2076 thread__put(thread);
2077 goto newline;
2078 }
2079 }
2080
2081 /*
2082 * XXX: Not having the associated syscall info or not finding/adding
2083 * the thread should never happen, but if it does...
2084 * fall thru and print it as a bpf_output event.
2085 */
2086 }
2087
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002088 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002089
Wang Nan1d6c9402016-02-26 09:31:55 +00002090 if (perf_evsel__is_bpf_output(evsel)) {
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002091 bpf_output__fprintf(trace, sample);
Wang Nan1d6c9402016-02-26 09:31:55 +00002092 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002093 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2094 trace__fprintf_sys_enter(trace, evsel, sample)) {
2095 event_format__fprintf(evsel->tp_format, sample->cpu,
2096 sample->raw_data, sample->raw_size,
2097 trace->output);
2098 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002099 }
2100
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002101newline:
Changbin Du51125a22018-03-13 18:40:01 +08002102 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002103
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002104 if (callchain_ret > 0)
2105 trace__fprintf_callchain(trace, sample);
2106 else if (callchain_ret < 0)
2107 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2108out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002109 return 0;
2110}
2111
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002112static void print_location(FILE *f, struct perf_sample *sample,
2113 struct addr_location *al,
2114 bool print_dso, bool print_sym)
2115{
2116
Namhyung Kimbb963e12017-02-17 17:17:38 +09002117 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002118 fprintf(f, "%s@", al->map->dso->long_name);
2119
Namhyung Kimbb963e12017-02-17 17:17:38 +09002120 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002121 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002122 al->addr - al->sym->start);
2123 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002124 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002125 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002126 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002127}
2128
2129static int trace__pgfault(struct trace *trace,
2130 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002131 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002132 struct perf_sample *sample)
2133{
2134 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002135 struct addr_location al;
2136 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002137 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002138 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002139 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002140
2141 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002142
2143 if (sample->callchain) {
2144 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2145 if (callchain_ret == 0) {
2146 if (callchain_cursor.nr < trace->min_stack)
2147 goto out_put;
2148 callchain_ret = 1;
2149 }
2150 }
2151
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002152 ttrace = thread__trace(thread, trace->output);
2153 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002154 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002155
2156 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2157 ttrace->pfmaj++;
2158 else
2159 ttrace->pfmin++;
2160
2161 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002162 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002163
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002164 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002165
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002166 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002167
2168 fprintf(trace->output, "%sfault [",
2169 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2170 "maj" : "min");
2171
2172 print_location(trace->output, sample, &al, false, true);
2173
2174 fprintf(trace->output, "] => ");
2175
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002176 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002177
2178 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002179 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002180
2181 if (al.map)
2182 map_type = 'x';
2183 else
2184 map_type = '?';
2185 }
2186
2187 print_location(trace->output, sample, &al, true, false);
2188
2189 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002190
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002191 if (callchain_ret > 0)
2192 trace__fprintf_callchain(trace, sample);
2193 else if (callchain_ret < 0)
2194 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002195out:
2196 err = 0;
2197out_put:
2198 thread__put(thread);
2199 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002200}
2201
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002202static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002203 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002204 struct perf_sample *sample)
2205{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002206 /*
2207 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2208 * and don't use sample->time unconditionally, we may end up having
2209 * some other event in the future without PERF_SAMPLE_TIME for good
2210 * reason, i.e. we may not be interested in its timestamps, just in
2211 * it taking place, picking some piece of information when it
2212 * appears in our event stream (vfs_getname comes to mind).
2213 */
2214 if (trace->base_time == 0 && !trace->full_time &&
2215 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002216 trace->base_time = sample->time;
2217}
2218
David Ahern6810fc92013-08-28 22:29:52 -06002219static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002220 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002221 struct perf_sample *sample,
2222 struct perf_evsel *evsel,
2223 struct machine *machine __maybe_unused)
2224{
2225 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002226 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002227 int err = 0;
2228
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002229 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002230
David Ahernaa07df62016-11-25 09:29:52 -07002231 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2232 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002233 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002234
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002235 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002236
David Ahern31605652013-12-04 19:41:41 -07002237 if (handler) {
2238 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002239 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002240 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002241out:
2242 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002243 return err;
2244}
2245
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002246static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002247{
2248 unsigned int rec_argc, i, j;
2249 const char **rec_argv;
2250 const char * const record_args[] = {
2251 "record",
2252 "-R",
2253 "-m", "1024",
2254 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002255 };
2256
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002257 const char * const sc_args[] = { "-e", };
2258 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2259 const char * const majpf_args[] = { "-e", "major-faults" };
2260 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2261 const char * const minpf_args[] = { "-e", "minor-faults" };
2262 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2263
David Ahern9aca7f12013-12-04 19:41:39 -07002264 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002265 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2266 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002267 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2268
2269 if (rec_argv == NULL)
2270 return -ENOMEM;
2271
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002272 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002273 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002274 rec_argv[j++] = record_args[i];
2275
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002276 if (trace->trace_syscalls) {
2277 for (i = 0; i < sc_args_nr; i++)
2278 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002279
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002280 /* event string may be different for older kernels - e.g., RHEL6 */
2281 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2282 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2283 else if (is_valid_tracepoint("syscalls:sys_enter"))
2284 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2285 else {
2286 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002287 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002288 return -1;
2289 }
David Ahern9aca7f12013-12-04 19:41:39 -07002290 }
David Ahern9aca7f12013-12-04 19:41:39 -07002291
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002292 if (trace->trace_pgfaults & TRACE_PFMAJ)
2293 for (i = 0; i < majpf_args_nr; i++)
2294 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002295
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002296 if (trace->trace_pgfaults & TRACE_PFMIN)
2297 for (i = 0; i < minpf_args_nr; i++)
2298 rec_argv[j++] = minpf_args[i];
2299
2300 for (i = 0; i < (unsigned int)argc; i++)
2301 rec_argv[j++] = argv[i];
2302
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002303 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002304}
2305
David Ahernbf2575c2013-10-08 21:26:53 -06002306static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2307
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002308static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002309{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002310 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002311
2312 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002313 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002314
2315 if (perf_evsel__field(evsel, "pathname") == NULL) {
2316 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002317 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002318 }
2319
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002320 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002321 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002322 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002323}
2324
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002325static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002326{
2327 struct perf_evsel *evsel;
2328 struct perf_event_attr attr = {
2329 .type = PERF_TYPE_SOFTWARE,
2330 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002331 };
2332
2333 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002334 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002335
2336 event_attr_init(&attr);
2337
2338 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002339 if (evsel)
2340 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002341
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002342 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002343}
2344
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002345static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2346{
2347 const u32 type = event->header.type;
2348 struct perf_evsel *evsel;
2349
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002350 if (type != PERF_RECORD_SAMPLE) {
2351 trace__process_event(trace, trace->host, event, sample);
2352 return;
2353 }
2354
2355 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2356 if (evsel == NULL) {
2357 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2358 return;
2359 }
2360
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002361 trace__set_base_time(trace, evsel, sample);
2362
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002363 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2364 sample->raw_data == NULL) {
2365 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2366 perf_evsel__name(evsel), sample->tid,
2367 sample->cpu, sample->raw_size);
2368 } else {
2369 tracepoint_handler handler = evsel->handler;
2370 handler(trace, evsel, event, sample);
2371 }
2372}
2373
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002374static int trace__add_syscall_newtp(struct trace *trace)
2375{
2376 int ret = -1;
2377 struct perf_evlist *evlist = trace->evlist;
2378 struct perf_evsel *sys_enter, *sys_exit;
2379
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002380 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002381 if (sys_enter == NULL)
2382 goto out;
2383
2384 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2385 goto out_delete_sys_enter;
2386
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002387 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002388 if (sys_exit == NULL)
2389 goto out_delete_sys_enter;
2390
2391 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2392 goto out_delete_sys_exit;
2393
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002394 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2395 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2396
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002397 perf_evlist__add(evlist, sys_enter);
2398 perf_evlist__add(evlist, sys_exit);
2399
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002400 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002401 /*
2402 * We're interested only in the user space callchain
2403 * leading to the syscall, allow overriding that for
2404 * debugging reasons using --kernel_syscall_callchains
2405 */
2406 sys_exit->attr.exclude_callchain_kernel = 1;
2407 }
2408
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002409 trace->syscalls.events.sys_enter = sys_enter;
2410 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002411
2412 ret = 0;
2413out:
2414 return ret;
2415
2416out_delete_sys_exit:
2417 perf_evsel__delete_priv(sys_exit);
2418out_delete_sys_enter:
2419 perf_evsel__delete_priv(sys_enter);
2420 goto out;
2421}
2422
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002423static int trace__set_ev_qualifier_filter(struct trace *trace)
2424{
2425 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002426 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002427 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2428 trace->ev_qualifier_ids.nr,
2429 trace->ev_qualifier_ids.entries);
2430
2431 if (filter == NULL)
2432 goto out_enomem;
2433
Mathieu Poirier3541c032016-09-16 08:44:04 -06002434 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2435 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002436 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002437 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002438 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002439
2440 free(filter);
2441out:
2442 return err;
2443out_enomem:
2444 errno = ENOMEM;
2445 goto out;
2446}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002447
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002448static int trace__set_filter_loop_pids(struct trace *trace)
2449{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002450 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002451 pid_t pids[32] = {
2452 getpid(),
2453 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002454 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2455
2456 while (thread && nr < ARRAY_SIZE(pids)) {
2457 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2458
2459 if (parent == NULL)
2460 break;
2461
2462 if (!strcmp(thread__comm_str(parent), "sshd")) {
2463 pids[nr++] = parent->tid;
2464 break;
2465 }
2466 thread = parent;
2467 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002468
2469 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2470}
2471
Namhyung Kimf15eb532012-10-05 14:02:16 +09002472static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002473{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002474 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002475 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002476 int err = -1, i;
2477 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002478 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002479 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002480
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002481 trace->live = true;
2482
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002483 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002484 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002485
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002486 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002487 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002488
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002489 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2490 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2491 if (pgfault_maj == NULL)
2492 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002493 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002494 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002495 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002496
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002497 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2498 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2499 if (pgfault_min == NULL)
2500 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002501 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002502 perf_evlist__add(evlist, pgfault_min);
2503 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002504
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002505 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002506 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2507 trace__sched_stat_runtime))
2508 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002509
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002510 /*
2511 * If a global cgroup was set, apply it to all the events without an
2512 * explicit cgroup. I.e.:
2513 *
2514 * trace -G A -e sched:*switch
2515 *
2516 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2517 * _and_ sched:sched_switch to the 'A' cgroup, while:
2518 *
2519 * trace -e sched:*switch -G A
2520 *
2521 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2522 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2523 * a cgroup (on the root cgroup, sys wide, etc).
2524 *
2525 * Multiple cgroups:
2526 *
2527 * trace -G A -e sched:*switch -G B
2528 *
2529 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2530 * to the 'B' cgroup.
2531 *
2532 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2533 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2534 */
2535 if (trace->cgroup)
2536 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2537
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002538 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2539 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002540 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002541 goto out_delete_evlist;
2542 }
2543
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002544 err = trace__symbols_init(trace, evlist);
2545 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002546 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002547 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002548 }
2549
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002550 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002551
Namhyung Kimf15eb532012-10-05 14:02:16 +09002552 signal(SIGCHLD, sig_handler);
2553 signal(SIGINT, sig_handler);
2554
2555 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002556 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002557 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002558 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002559 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002560 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002561 }
2562 }
2563
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002564 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002565 if (err < 0)
2566 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002567
Wang Nanba504232016-02-26 09:31:54 +00002568 err = bpf__apply_obj_config();
2569 if (err) {
2570 char errbuf[BUFSIZ];
2571
2572 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2573 pr_err("ERROR: Apply config to BPF failed: %s\n",
2574 errbuf);
2575 goto out_error_open;
2576 }
2577
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002578 /*
2579 * Better not use !target__has_task() here because we need to cover the
2580 * case where no threads were specified in the command line, but a
2581 * workload was, and in that case we will fill in the thread_map when
2582 * we fork the workload in perf_evlist__prepare_workload.
2583 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002584 if (trace->filter_pids.nr > 0)
2585 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002586 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002587 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002588
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002589 if (err < 0)
2590 goto out_error_mem;
2591
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002592 if (trace->ev_qualifier_ids.nr > 0) {
2593 err = trace__set_ev_qualifier_filter(trace);
2594 if (err < 0)
2595 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002596
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002597 pr_debug("event qualifier tracepoint filter: %s\n",
2598 trace->syscalls.events.sys_exit->filter);
2599 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002600
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002601 err = perf_evlist__apply_filters(evlist, &evsel);
2602 if (err < 0)
2603 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002604
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002605 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002606 if (err < 0)
2607 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002608
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002609 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002610 perf_evlist__enable(evlist);
2611
Namhyung Kimf15eb532012-10-05 14:02:16 +09002612 if (forks)
2613 perf_evlist__start_workload(evlist);
2614
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002615 if (trace->opts.initial_delay) {
2616 usleep(trace->opts.initial_delay * 1000);
2617 perf_evlist__enable(evlist);
2618 }
2619
Jiri Olsae13798c2015-06-23 00:36:02 +02002620 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002621 evlist->threads->nr > 1 ||
2622 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002623
2624 /*
2625 * Now that we already used evsel->attr to ask the kernel to setup the
2626 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2627 * trace__resolve_callchain(), allowing per-event max-stack settings
2628 * to override an explicitely set --max-stack global setting.
2629 */
2630 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002631 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002632 evsel->attr.sample_max_stack == 0)
2633 evsel->attr.sample_max_stack = trace->max_stack;
2634 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002635again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002636 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002637
2638 for (i = 0; i < evlist->nr_mmaps; i++) {
2639 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002640 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002641
Kan Liangd7f55c62018-03-01 18:08:59 -05002642 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002643 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002644 continue;
2645
Kan Liang0019dc872018-03-06 10:36:06 -05002646 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002647 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002648
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002649 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002650
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002651 err = perf_evlist__parse_sample(evlist, event, &sample);
2652 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002653 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002654 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002655 }
2656
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002657 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002658next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002659 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002660
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002661 if (interrupted)
2662 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002663
2664 if (done && !draining) {
2665 perf_evlist__disable(evlist);
2666 draining = true;
2667 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002668 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002669 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002670 }
2671
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002672 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002673 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002674
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002675 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2676 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2677 draining = true;
2678
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002679 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002680 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002681 } else {
2682 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002683 }
2684
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002685out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002686 thread__zput(trace->current);
2687
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002688 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002689
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002690 if (!err) {
2691 if (trace->summary)
2692 trace__fprintf_thread_summary(trace, trace->output);
2693
2694 if (trace->show_tool_stats) {
2695 fprintf(trace->output, "Stats:\n "
2696 " vfs_getname : %" PRIu64 "\n"
2697 " proc_getname: %" PRIu64 "\n",
2698 trace->stats.vfs_getname,
2699 trace->stats.proc_getname);
2700 }
2701 }
David Ahernbf2575c2013-10-08 21:26:53 -06002702
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002703out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002704 trace__symbols__exit(trace);
2705
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002706 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002707 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002708 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002709 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002710 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002711{
2712 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002713
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002714out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002715 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002716 goto out_error;
2717
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002718out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002719 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002720 goto out_error;
2721
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002722out_error_mmap:
2723 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2724 goto out_error;
2725
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002726out_error_open:
2727 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2728
2729out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002730 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302731 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002732
2733out_error_apply_filters:
2734 fprintf(trace->output,
2735 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2736 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002737 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002738 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002739}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002740out_error_mem:
2741 fprintf(trace->output, "Not enough memory to run!\n");
2742 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002743
2744out_errno:
2745 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2746 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002747}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002748
David Ahern6810fc92013-08-28 22:29:52 -06002749static int trace__replay(struct trace *trace)
2750{
2751 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002752 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002753 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002754 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002755 .file = {
2756 .path = input_name,
2757 },
2758 .mode = PERF_DATA_MODE_READ,
2759 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002760 };
David Ahern6810fc92013-08-28 22:29:52 -06002761 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002762 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002763 int err = -1;
2764
2765 trace->tool.sample = trace__process_sample;
2766 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002767 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002768 trace->tool.comm = perf_event__process_comm;
2769 trace->tool.exit = perf_event__process_exit;
2770 trace->tool.fork = perf_event__process_fork;
2771 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302772 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002773 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302774 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002775
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002776 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002777 trace->tool.ordering_requires_timestamps = true;
2778
2779 /* add tid to output */
2780 trace->multiple_threads = true;
2781
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002782 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002783 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002784 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002785
David Ahernaa07df62016-11-25 09:29:52 -07002786 if (trace->opts.target.pid)
2787 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2788
2789 if (trace->opts.target.tid)
2790 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2791
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002792 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002793 goto out;
2794
David Ahern8fb598e2013-09-28 13:13:00 -06002795 trace->host = &session->machines.host;
2796
David Ahern6810fc92013-08-28 22:29:52 -06002797 err = perf_session__set_tracepoints_handlers(session, handlers);
2798 if (err)
2799 goto out;
2800
Namhyung Kim003824e2013-11-12 15:25:00 +09002801 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2802 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002803 /* older kernels have syscalls tp versus raw_syscalls */
2804 if (evsel == NULL)
2805 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2806 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002807
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002808 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002809 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002810 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002811 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2812 goto out;
2813 }
2814
2815 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2816 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002817 if (evsel == NULL)
2818 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2819 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002820 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002821 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002822 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002823 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002824 goto out;
2825 }
2826
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002827 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002828 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2829 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2830 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2831 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2832 evsel->handler = trace__pgfault;
2833 }
2834
David Ahern6810fc92013-08-28 22:29:52 -06002835 setup_pager();
2836
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002837 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002838 if (err)
2839 pr_err("Failed to process events, error %d", err);
2840
David Ahernbf2575c2013-10-08 21:26:53 -06002841 else if (trace->summary)
2842 trace__fprintf_thread_summary(trace, trace->output);
2843
David Ahern6810fc92013-08-28 22:29:52 -06002844out:
2845 perf_session__delete(session);
2846
2847 return err;
2848}
2849
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002850static size_t trace__fprintf_threads_header(FILE *fp)
2851{
2852 size_t printed;
2853
Pekka Enberg99ff7152013-11-12 16:42:14 +02002854 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002855
2856 return printed;
2857}
2858
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002859DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2860 struct stats *stats;
2861 double msecs;
2862 int syscall;
2863)
2864{
2865 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2866 struct stats *stats = source->priv;
2867
2868 entry->syscall = source->i;
2869 entry->stats = stats;
2870 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2871}
2872
David Ahernbf2575c2013-10-08 21:26:53 -06002873static size_t thread__dump_stats(struct thread_trace *ttrace,
2874 struct trace *trace, FILE *fp)
2875{
David Ahernbf2575c2013-10-08 21:26:53 -06002876 size_t printed = 0;
2877 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002878 struct rb_node *nd;
2879 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002880
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002881 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002882 return 0;
2883
2884 printed += fprintf(fp, "\n");
2885
Milian Wolff834fd462015-08-06 11:24:29 +02002886 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2887 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2888 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002889
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002890 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002891 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002892 if (stats) {
2893 double min = (double)(stats->min) / NSEC_PER_MSEC;
2894 double max = (double)(stats->max) / NSEC_PER_MSEC;
2895 double avg = avg_stats(stats);
2896 double pct;
2897 u64 n = (u64) stats->n;
2898
2899 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2900 avg /= NSEC_PER_MSEC;
2901
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002902 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002903 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002904 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002905 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002906 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002907 }
David Ahernbf2575c2013-10-08 21:26:53 -06002908 }
2909
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002910 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002911 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002912
2913 return printed;
2914}
2915
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002916static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002917{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002918 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002919 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002920 double ratio;
2921
2922 if (ttrace == NULL)
2923 return 0;
2924
2925 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2926
Pekka Enberg15e65c62013-11-14 18:43:30 +02002927 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002928 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002929 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002930 if (ttrace->pfmaj)
2931 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2932 if (ttrace->pfmin)
2933 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002934 if (trace->sched)
2935 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2936 else if (fputc('\n', fp) != EOF)
2937 ++printed;
2938
David Ahernbf2575c2013-10-08 21:26:53 -06002939 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002940
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002941 return printed;
2942}
David Ahern896cbb52013-09-28 13:12:59 -06002943
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002944static unsigned long thread__nr_events(struct thread_trace *ttrace)
2945{
2946 return ttrace ? ttrace->nr_events : 0;
2947}
2948
2949DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2950 struct thread *thread;
2951)
2952{
2953 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002954}
2955
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002956static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2957{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002958 size_t printed = trace__fprintf_threads_header(fp);
2959 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002960 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002961
Kan Liang91e467b2017-09-10 19:23:14 -07002962 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2963 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2964
2965 if (threads == NULL) {
2966 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2967 return 0;
2968 }
2969
2970 resort_rb__for_each_entry(nd, threads)
2971 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2972
2973 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002974 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002975 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002976}
2977
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002978static int trace__set_duration(const struct option *opt, const char *str,
2979 int unset __maybe_unused)
2980{
2981 struct trace *trace = opt->value;
2982
2983 trace->duration_filter = atof(str);
2984 return 0;
2985}
2986
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002987static int trace__set_filter_pids(const struct option *opt, const char *str,
2988 int unset __maybe_unused)
2989{
2990 int ret = -1;
2991 size_t i;
2992 struct trace *trace = opt->value;
2993 /*
2994 * FIXME: introduce a intarray class, plain parse csv and create a
2995 * { int nr, int entries[] } struct...
2996 */
2997 struct intlist *list = intlist__new(str);
2998
2999 if (list == NULL)
3000 return -1;
3001
3002 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3003 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3004
3005 if (trace->filter_pids.entries == NULL)
3006 goto out;
3007
3008 trace->filter_pids.entries[0] = getpid();
3009
3010 for (i = 1; i < trace->filter_pids.nr; ++i)
3011 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3012
3013 intlist__delete(list);
3014 ret = 0;
3015out:
3016 return ret;
3017}
3018
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003019static int trace__open_output(struct trace *trace, const char *filename)
3020{
3021 struct stat st;
3022
3023 if (!stat(filename, &st) && st.st_size) {
3024 char oldname[PATH_MAX];
3025
3026 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3027 unlink(oldname);
3028 rename(filename, oldname);
3029 }
3030
3031 trace->output = fopen(filename, "w");
3032
3033 return trace->output == NULL ? -errno : 0;
3034}
3035
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003036static int parse_pagefaults(const struct option *opt, const char *str,
3037 int unset __maybe_unused)
3038{
3039 int *trace_pgfaults = opt->value;
3040
3041 if (strcmp(str, "all") == 0)
3042 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3043 else if (strcmp(str, "maj") == 0)
3044 *trace_pgfaults |= TRACE_PFMAJ;
3045 else if (strcmp(str, "min") == 0)
3046 *trace_pgfaults |= TRACE_PFMIN;
3047 else
3048 return -1;
3049
3050 return 0;
3051}
3052
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003053static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3054{
3055 struct perf_evsel *evsel;
3056
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003057 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003058 evsel->handler = handler;
3059}
3060
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003061static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist)
3062{
3063 struct perf_evsel *evsel;
3064
3065 evlist__for_each_entry(evlist, evsel) {
3066 if (evsel->priv || !evsel->tp_format)
3067 continue;
3068
3069 if (strcmp(evsel->tp_format->system, "syscalls"))
3070 continue;
3071
3072 if (perf_evsel__init_syscall_tp(evsel))
3073 return -1;
3074
3075 if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
3076 struct syscall_tp *sc = evsel->priv;
3077
3078 if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
3079 return -1;
3080 } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
3081 struct syscall_tp *sc = evsel->priv;
3082
3083 if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
3084 return -1;
3085 }
3086 }
3087
3088 return 0;
3089}
3090
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003091/*
3092 * XXX: Hackish, just splitting the combined -e+--event (syscalls
3093 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
3094 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
3095 *
3096 * It'd be better to introduce a parse_options() variant that would return a
3097 * list with the terms it didn't match to an event...
3098 */
3099static int trace__parse_events_option(const struct option *opt, const char *str,
3100 int unset __maybe_unused)
3101{
3102 struct trace *trace = (struct trace *)opt->value;
3103 const char *s = str;
3104 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003105 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003106 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
3107 char group_name[PATH_MAX];
3108
3109 if (strace_groups_dir == NULL)
3110 return -1;
3111
3112 if (*s == '!') {
3113 ++s;
3114 trace->not_ev_qualifier = true;
3115 }
3116
3117 while (1) {
3118 if ((sep = strchr(s, ',')) != NULL)
3119 *sep = '\0';
3120
3121 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003122 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3123 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003124 list = 1;
3125 } else {
3126 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3127 if (access(group_name, R_OK) == 0)
3128 list = 1;
3129 }
3130
3131 if (lists[list]) {
3132 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3133 } else {
3134 lists[list] = malloc(len);
3135 if (lists[list] == NULL)
3136 goto out;
3137 strcpy(lists[list], s);
3138 }
3139
3140 if (!sep)
3141 break;
3142
3143 *sep = ',';
3144 s = sep + 1;
3145 }
3146
3147 if (lists[1] != NULL) {
3148 struct strlist_config slist_config = {
3149 .dirname = strace_groups_dir,
3150 };
3151
3152 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3153 if (trace->ev_qualifier == NULL) {
3154 fputs("Not enough memory to parse event qualifier", trace->output);
3155 goto out;
3156 }
3157
3158 if (trace__validate_ev_qualifier(trace))
3159 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003160 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003161 }
3162
3163 err = 0;
3164
3165 if (lists[0]) {
3166 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3167 "event selector. use 'perf list' to list available events",
3168 parse_events_option);
3169 err = parse_events_option(&o, lists[0], 0);
3170 }
3171out:
3172 if (sep)
3173 *sep = ',';
3174
3175 return err;
3176}
3177
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003178static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3179{
3180 struct trace *trace = opt->value;
3181
3182 if (!list_empty(&trace->evlist->entries))
3183 return parse_cgroups(opt, str, unset);
3184
3185 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3186
3187 return 0;
3188}
3189
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003190int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003191{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003192 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003193 "perf trace [<options>] [<command>]",
3194 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003195 "perf trace record [<options>] [<command>]",
3196 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003197 NULL
3198 };
3199 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003200 .syscalls = {
3201 . max = -1,
3202 },
3203 .opts = {
3204 .target = {
3205 .uid = UINT_MAX,
3206 .uses_mmap = true,
3207 },
3208 .user_freq = UINT_MAX,
3209 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003210 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003211 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003212 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003213 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003214 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003215 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003216 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003217 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003218 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003219 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003220 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003221 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003222 OPT_CALLBACK('e', "event", &trace, "event",
3223 "event/syscall selector. use 'perf list' to list available events",
3224 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003225 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3226 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003227 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003228 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3229 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003230 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003231 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003232 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3233 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003234 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003235 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003236 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3237 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003238 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003239 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003240 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003241 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003242 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003243 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003244 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3245 "number of mmap data pages",
3246 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003247 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003248 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003249 OPT_CALLBACK(0, "duration", &trace, "float",
3250 "show only events with duration > N.M ms",
3251 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003252 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003253 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003254 OPT_BOOLEAN('T', "time", &trace.full_time,
3255 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003256 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3257 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003258 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3259 "Show only syscall summary with statistics"),
3260 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3261 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003262 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3263 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003264 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003265 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003266 OPT_CALLBACK(0, "call-graph", &trace.opts,
3267 "record_mode[,record_size]", record_callchain_help,
3268 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003269 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3270 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003271 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3272 "Set the minimum stack depth when parsing the callchain, "
3273 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003274 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3275 "Set the maximum stack depth when parsing the callchain, "
3276 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003277 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003278 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3279 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003280 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3281 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003282 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3283 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003284 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3285 "ms to wait before starting measurement after program "
3286 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003287 OPT_END()
3288 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003289 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003290 bool mmap_pages_user_set = true;
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003291 struct perf_evsel *evsel;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003292 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003293 int err = -1;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003294 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003295
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003296 signal(SIGSEGV, sighandler_dump_stack);
3297 signal(SIGFPE, sighandler_dump_stack);
3298
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003299 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003300 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003301
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003302 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003303 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003304 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003305 goto out;
3306 }
3307
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003308 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3309 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003310
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003311 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3312 usage_with_options_msg(trace_usage, trace_options,
3313 "cgroup monitoring only available in system-wide mode");
3314 }
3315
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003316 evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__");
3317 if (IS_ERR(evsel)) {
3318 bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf));
Arnaldo Carvalho de Meloe0b6d2e2018-08-07 15:40:13 -03003319 pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf);
3320 goto out;
3321 }
3322
Arnaldo Carvalho de Melod3d1c4bdf52018-08-07 16:21:44 -03003323 if (evsel) {
3324 if (perf_evsel__init_augmented_syscall_tp(evsel) ||
3325 perf_evsel__init_augmented_syscall_tp_args(evsel))
3326 goto out;
3327 trace.syscalls.events.augmented = evsel;
3328 }
3329
Wang Nand7888572016-04-08 15:07:24 +00003330 err = bpf__setup_stdout(trace.evlist);
3331 if (err) {
3332 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3333 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3334 goto out;
3335 }
3336
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003337 err = -1;
3338
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003339 if (trace.trace_pgfaults) {
3340 trace.opts.sample_address = true;
3341 trace.opts.sample_time = true;
3342 }
3343
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003344 if (trace.opts.mmap_pages == UINT_MAX)
3345 mmap_pages_user_set = false;
3346
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003347 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003348 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003349 max_stack_user_set = false;
3350 }
3351
3352#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003353 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003354 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003355 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003356#endif
3357
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003358 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003359 if (!mmap_pages_user_set && geteuid() == 0)
3360 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3361
Milian Wolff566a0882016-04-08 13:34:15 +02003362 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003363 }
Milian Wolff566a0882016-04-08 13:34:15 +02003364
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003365 if (trace.evlist->nr_entries > 0) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003366 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003367 if (evlist__set_syscall_tp_fields(trace.evlist)) {
3368 perror("failed to set syscalls:* tracepoint fields");
3369 goto out;
3370 }
3371 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003372
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003373 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3374 return trace__record(&trace, argc-1, &argv[1]);
3375
3376 /* summary_only implies summary option, but don't overwrite summary if set */
3377 if (trace.summary_only)
3378 trace.summary = trace.summary_only;
3379
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003380 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3381 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003382 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003383 }
3384
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003385 if (output_name != NULL) {
3386 err = trace__open_output(&trace, output_name);
3387 if (err < 0) {
3388 perror("failed to create output file");
3389 goto out;
3390 }
3391 }
3392
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003393 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003394 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;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003398 }
3399
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003400 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003401 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003402 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003403 fprintf(trace.output, "%s", bf);
3404 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003405 }
3406
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003407 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003408 trace.opts.target.system_wide = true;
3409
David Ahern6810fc92013-08-28 22:29:52 -06003410 if (input_name)
3411 err = trace__replay(&trace);
3412 else
3413 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003414
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003415out_close:
3416 if (output_name != NULL)
3417 fclose(trace.output);
3418out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003419 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003420}