blob: 5d841114a745de2b08f56023a290e5951a86318d [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
Arnaldo Carvalho de Melo75d1e302018-08-21 12:00:39 -03001100static size_t syscall_arg__scnprintf_augmented_string(struct syscall_arg *arg, char *bf, size_t size)
1101{
1102 struct augmented_arg *augmented_arg = arg->augmented.args;
1103
1104 return scnprintf(bf, size, "%.*s", augmented_arg->size, augmented_arg->value);
1105}
1106
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001107static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1108 struct syscall_arg *arg)
1109{
1110 unsigned long ptr = arg->val;
1111
Arnaldo Carvalho de Melo75d1e302018-08-21 12:00:39 -03001112 if (arg->augmented.args)
1113 return syscall_arg__scnprintf_augmented_string(arg, bf, size);
1114
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001115 if (!arg->trace->vfs_getname)
1116 return scnprintf(bf, size, "%#x", ptr);
1117
1118 thread__set_filename_pos(arg->thread, bf, ptr);
1119 return 0;
1120}
1121
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001122static bool trace__filter_duration(struct trace *trace, double t)
1123{
1124 return t < (trace->duration_filter * NSEC_PER_MSEC);
1125}
1126
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001127static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128{
1129 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1130
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001131 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001132}
1133
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001134/*
1135 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1136 * using ttrace->entry_time for a thread that receives a sys_exit without
1137 * first having received a sys_enter ("poll" issued before tracing session
1138 * starts, lost sys_enter exit due to ring buffer overflow).
1139 */
1140static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1141{
1142 if (tstamp > 0)
1143 return __trace__fprintf_tstamp(trace, tstamp, fp);
1144
1145 return fprintf(fp, " ? ");
1146}
1147
Namhyung Kimf15eb532012-10-05 14:02:16 +09001148static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001149static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001150
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001151static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001152{
1153 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001154 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001155}
1156
Arnaldo Carvalho de Melo6dcbd212018-08-21 11:40:09 -03001157static size_t trace__fprintf_comm_tid(struct trace *trace, struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001158{
Arnaldo Carvalho de Melo6dcbd212018-08-21 11:40:09 -03001159 size_t printed = 0;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001160
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001161 if (trace->multiple_threads) {
1162 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001163 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001164 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001165 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001166
1167 return printed;
1168}
1169
Arnaldo Carvalho de Melo6dcbd212018-08-21 11:40:09 -03001170static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
1171 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
1172{
1173 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
1174 printed += fprintf_duration(duration, duration_calculated, fp);
1175 return printed + trace__fprintf_comm_tid(trace, thread, fp);
1176}
1177
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001178static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001179 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001180{
1181 int ret = 0;
1182
1183 switch (event->header.type) {
1184 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001185 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001186 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001187 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001188 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001189 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001190 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001191 break;
1192 }
1193
1194 return ret;
1195}
1196
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001197static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001198 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001199 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001200 struct machine *machine)
1201{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001202 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001203 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001204}
1205
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001206static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1207{
1208 struct machine *machine = vmachine;
1209
1210 if (machine->kptr_restrict_warned)
1211 return NULL;
1212
1213 if (symbol_conf.kptr_restrict) {
1214 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1215 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1216 "Kernel samples will not be resolved.\n");
1217 machine->kptr_restrict_warned = true;
1218 return NULL;
1219 }
1220
1221 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1222}
1223
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001224static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1225{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001226 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001227
1228 if (err)
1229 return err;
1230
David Ahern8fb598e2013-09-28 13:13:00 -06001231 trace->host = machine__new_host();
1232 if (trace->host == NULL)
1233 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001234
Andrei Vagincbd5c172017-11-07 16:22:46 -08001235 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1236 if (err < 0)
1237 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001238
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001239 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001240 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001241 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001242out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001243 if (err)
1244 symbol__exit();
1245
1246 return err;
1247}
1248
Andrei Vagin33974a42017-11-07 16:22:45 -08001249static void trace__symbols__exit(struct trace *trace)
1250{
1251 machine__exit(trace->host);
1252 trace->host = NULL;
1253
1254 symbol__exit();
1255}
1256
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001257static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1258{
1259 int idx;
1260
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001261 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1262 nr_args = sc->fmt->nr_args;
1263
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001264 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1265 if (sc->arg_fmt == NULL)
1266 return -1;
1267
1268 for (idx = 0; idx < nr_args; ++idx) {
1269 if (sc->fmt)
1270 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1271 }
1272
1273 sc->nr_args = nr_args;
1274 return 0;
1275}
1276
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001277static int syscall__set_arg_fmts(struct syscall *sc)
1278{
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001279 struct format_field *field, *last_field = NULL;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001280 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001281
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001282 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001283 last_field = field;
1284
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001285 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1286 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001287
1288 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001289 (strcmp(field->name, "filename") == 0 ||
1290 strcmp(field->name, "path") == 0 ||
1291 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001292 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001293 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001294 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001295 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001296 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001297 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001298 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001299 else if ((strcmp(field->type, "int") == 0 ||
1300 strcmp(field->type, "unsigned int") == 0 ||
1301 strcmp(field->type, "long") == 0) &&
1302 (len = strlen(field->name)) >= 2 &&
1303 strcmp(field->name + len - 2, "fd") == 0) {
1304 /*
1305 * /sys/kernel/tracing/events/syscalls/sys_enter*
1306 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1307 * 65 int
1308 * 23 unsigned int
1309 * 7 unsigned long
1310 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001311 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001312 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001313 }
1314
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001315 if (last_field)
1316 sc->args_size = last_field->offset + last_field->size;
1317
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001318 return 0;
1319}
1320
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001321static int trace__read_syscall_info(struct trace *trace, int id)
1322{
1323 char tp_name[128];
1324 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001325 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001326
1327 if (name == NULL)
1328 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001329
1330 if (id > trace->syscalls.max) {
1331 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1332
1333 if (nsyscalls == NULL)
1334 return -1;
1335
1336 if (trace->syscalls.max != -1) {
1337 memset(nsyscalls + trace->syscalls.max + 1, 0,
1338 (id - trace->syscalls.max) * sizeof(*sc));
1339 } else {
1340 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1341 }
1342
1343 trace->syscalls.table = nsyscalls;
1344 trace->syscalls.max = id;
1345 }
1346
1347 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001348 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001349
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001350 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001351
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001352 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001353 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001354
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001355 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001356 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001357 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001358 }
1359
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001360 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1361 return -1;
1362
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001363 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001364 return -1;
1365
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001366 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001367 /*
1368 * We need to check and discard the first variable '__syscall_nr'
1369 * or 'nr' that mean the syscall number. It is needless here.
1370 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1371 */
1372 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001373 sc->args = sc->args->next;
1374 --sc->nr_args;
1375 }
1376
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001377 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001378 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001379
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001380 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001381}
1382
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001383static int trace__validate_ev_qualifier(struct trace *trace)
1384{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001385 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001386 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001387 struct str_node *pos;
1388
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001389 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1390 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1391 sizeof(trace->ev_qualifier_ids.entries[0]));
1392
1393 if (trace->ev_qualifier_ids.entries == NULL) {
1394 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1395 trace->output);
1396 err = -EINVAL;
1397 goto out;
1398 }
1399
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001400 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001401 i = 0;
1402
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001403 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001404 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001405 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001406
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001407 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001408 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1409 if (id >= 0)
1410 goto matches;
1411
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001412 if (err == 0) {
1413 fputs("Error:\tInvalid syscall ", trace->output);
1414 err = -EINVAL;
1415 } else {
1416 fputs(", ", trace->output);
1417 }
1418
1419 fputs(sc, trace->output);
1420 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001421matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001422 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001423 if (match_next == -1)
1424 continue;
1425
1426 while (1) {
1427 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1428 if (id < 0)
1429 break;
1430 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1431 void *entries;
1432
1433 nr_allocated += 8;
1434 entries = realloc(trace->ev_qualifier_ids.entries,
1435 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1436 if (entries == NULL) {
1437 err = -ENOMEM;
1438 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1439 goto out_free;
1440 }
1441 trace->ev_qualifier_ids.entries = entries;
1442 }
1443 trace->ev_qualifier_ids.nr++;
1444 trace->ev_qualifier_ids.entries[i++] = id;
1445 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001446 }
1447
1448 if (err < 0) {
1449 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1450 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001451out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001452 zfree(&trace->ev_qualifier_ids.entries);
1453 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001454 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001455out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001456 return err;
1457}
1458
David Ahern55d43bca2015-02-19 15:00:22 -05001459/*
1460 * args is to be interpreted as a series of longs but we need to handle
1461 * 8-byte unaligned accesses. args points to raw_data within the event
1462 * and raw_data is guaranteed to be 8-byte unaligned because it is
1463 * preceded by raw_size which is a u32. So we need to copy args to a temp
1464 * variable to read it. Most notably this avoids extended load instructions
1465 * on unaligned addresses
1466 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001467unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001468{
1469 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001470 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001471
1472 memcpy(&val, p, sizeof(val));
1473 return val;
1474}
1475
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001476static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1477 struct syscall_arg *arg)
1478{
1479 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1480 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1481
1482 return scnprintf(bf, size, "arg%d: ", arg->idx);
1483}
1484
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001485static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1486 struct syscall_arg *arg, unsigned long val)
1487{
1488 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1489 arg->val = val;
1490 if (sc->arg_fmt[arg->idx].parm)
1491 arg->parm = sc->arg_fmt[arg->idx].parm;
1492 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1493 }
1494 return scnprintf(bf, size, "%ld", val);
1495}
1496
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001497static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001498 unsigned char *args, void *augmented_args, int augmented_args_size,
1499 struct trace *trace, struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001500{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001501 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001502 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001503 u8 bit = 1;
1504 struct syscall_arg arg = {
1505 .args = args,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001506 .augmented = {
1507 .size = augmented_args_size,
1508 .args = augmented_args,
1509 },
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001510 .idx = 0,
1511 .mask = 0,
1512 .trace = trace,
1513 .thread = thread,
1514 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001515 struct thread_trace *ttrace = thread__priv(thread);
1516
1517 /*
1518 * Things like fcntl will set this in its 'cmd' formatter to pick the
1519 * right formatter for the return value (an fd? file flags?), which is
1520 * not needed for syscalls that always return a given type, say an fd.
1521 */
1522 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001524 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001525 struct format_field *field;
1526
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001527 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001528 field = field->next, ++arg.idx, bit <<= 1) {
1529 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001530 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001531
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001532 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001533
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001534 /*
1535 * Suppress this argument if its value is zero and
1536 * and we don't have a string associated in an
1537 * strarray for it.
1538 */
David Ahern55d43bca2015-02-19 15:00:22 -05001539 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001540 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001541 (sc->arg_fmt[arg.idx].show_zero ||
1542 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001543 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1544 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001545 continue;
1546
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001547 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001548 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001549 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001550 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001551 } else if (IS_ERR(sc->tp_format)) {
1552 /*
1553 * If we managed to read the tracepoint /format file, then we
1554 * may end up not having any args, like with gettid(), so only
1555 * print the raw args when we didn't manage to read it.
1556 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001557 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001558 if (arg.mask & bit)
1559 goto next_arg;
1560 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001561 if (printed)
1562 printed += scnprintf(bf + printed, size - printed, ", ");
1563 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001564 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1565next_arg:
1566 ++arg.idx;
1567 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001568 }
1569 }
1570
1571 return printed;
1572}
1573
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001574typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001575 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001576 struct perf_sample *sample);
1577
1578static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001579 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001580{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001581
1582 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001583
1584 /*
1585 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1586 * before that, leaving at a higher verbosity level till that is
1587 * explained. Reproduced with plain ftrace with:
1588 *
1589 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1590 * grep "NR -1 " /t/trace_pipe
1591 *
1592 * After generating some load on the machine.
1593 */
1594 if (verbose > 1) {
1595 static u64 n;
1596 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1597 id, perf_evsel__name(evsel), ++n);
1598 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001599 return NULL;
1600 }
1601
1602 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1603 trace__read_syscall_info(trace, id))
1604 goto out_cant_read;
1605
1606 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1607 goto out_cant_read;
1608
1609 return &trace->syscalls.table[id];
1610
1611out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001612 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001613 fprintf(trace->output, "Problems reading syscall %d", id);
1614 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1615 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1616 fputs(" information\n", trace->output);
1617 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001618 return NULL;
1619}
1620
David Ahernbf2575c2013-10-08 21:26:53 -06001621static void thread__update_stats(struct thread_trace *ttrace,
1622 int id, struct perf_sample *sample)
1623{
1624 struct int_node *inode;
1625 struct stats *stats;
1626 u64 duration = 0;
1627
1628 inode = intlist__findnew(ttrace->syscall_stats, id);
1629 if (inode == NULL)
1630 return;
1631
1632 stats = inode->priv;
1633 if (stats == NULL) {
1634 stats = malloc(sizeof(struct stats));
1635 if (stats == NULL)
1636 return;
1637 init_stats(stats);
1638 inode->priv = stats;
1639 }
1640
1641 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1642 duration = sample->time - ttrace->entry_time;
1643
1644 update_stats(stats, duration);
1645}
1646
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001647static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001648{
1649 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001650 size_t printed;
1651
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001652 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001653 return 0;
1654
1655 ttrace = thread__priv(trace->current);
1656
1657 if (!ttrace->entry_pending)
1658 return 0;
1659
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001660 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001661 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1662 ttrace->entry_pending = false;
1663
1664 return printed;
1665}
1666
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001667static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1668 struct perf_sample *sample, struct thread *thread)
1669{
1670 int printed = 0;
1671
1672 if (trace->print_sample) {
1673 double ts = (double)sample->time / NSEC_PER_MSEC;
1674
1675 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1676 perf_evsel__name(evsel), ts,
1677 thread__comm_str(thread),
1678 sample->pid, sample->tid, sample->cpu);
1679 }
1680
1681 return printed;
1682}
1683
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001684static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001685 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001686 struct perf_sample *sample)
1687{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001688 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001689 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001690 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001691 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001692 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001693 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001694 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001695
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001696 if (sc == NULL)
1697 return -1;
1698
David Ahern8fb598e2013-09-28 13:13:00 -06001699 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001700 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001701 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001702 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001703
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001704 trace__fprintf_sample(trace, evsel, sample, thread);
1705
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001706 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001707
1708 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001709 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001710 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001711 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001712 }
1713
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001714 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001715 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001716
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001717 ttrace->entry_time = sample->time;
1718 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001719 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001720
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001721 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001722 args, NULL, 0, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001723
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001724 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001725 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001726 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001727 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001728 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001729 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001730 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001731 /* See trace__vfs_getname & trace__sys_exit */
1732 ttrace->filename.pending_open = false;
1733 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001734
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001735 if (trace->current != thread) {
1736 thread__put(trace->current);
1737 trace->current = thread__get(thread);
1738 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001739 err = 0;
1740out_put:
1741 thread__put(thread);
1742 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001743}
1744
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001745static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1746 struct perf_sample *sample)
1747{
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001748 struct thread_trace *ttrace;
1749 struct thread *thread;
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001750 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
1751 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001752 char msg[1024];
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001753 void *args, *augmented_args = NULL;
1754 int augmented_args_size;
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001755
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001756 if (sc == NULL)
1757 return -1;
1758
1759 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1760 ttrace = thread__trace(thread, trace->output);
1761 /*
1762 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1763 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1764 */
1765 if (ttrace == NULL)
1766 goto out_put;
1767
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001768 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo7a983a02018-08-20 17:58:17 -03001769 augmented_args_size = sample->raw_size - sc->args_size;
1770 if (augmented_args_size > 0)
1771 augmented_args = sample->raw_data + sc->args_size;
1772
1773 syscall__scnprintf_args(sc, msg, sizeof(msg), args, augmented_args, augmented_args_size, trace, thread);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001774 fprintf(trace->output, "%s", msg);
1775 err = 0;
1776out_put:
1777 thread__put(thread);
1778 return err;
1779}
1780
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001781static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1782 struct perf_sample *sample,
1783 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001784{
1785 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301786 int max_stack = evsel->attr.sample_max_stack ?
1787 evsel->attr.sample_max_stack :
1788 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001789
1790 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301791 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001792 return -1;
1793
1794 return 0;
1795}
1796
1797static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1798{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001799 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001800 const unsigned int print_opts = EVSEL__PRINT_SYM |
1801 EVSEL__PRINT_DSO |
1802 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001803
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001804 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001805}
1806
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001807static const char *errno_to_name(struct perf_evsel *evsel, int err)
1808{
1809 struct perf_env *env = perf_evsel__env(evsel);
1810 const char *arch_name = perf_env__arch(env);
1811
1812 return arch_syscalls__strerrno(arch_name, err);
1813}
1814
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001815static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001816 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001817 struct perf_sample *sample)
1818{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001819 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001820 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001821 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001822 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001823 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001824 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001825 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001826
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001827 if (sc == NULL)
1828 return -1;
1829
David Ahern8fb598e2013-09-28 13:13:00 -06001830 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001831 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001832 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001833 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001834
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001835 trace__fprintf_sample(trace, evsel, sample, thread);
1836
David Ahernbf2575c2013-10-08 21:26:53 -06001837 if (trace->summary)
1838 thread__update_stats(ttrace, id, sample);
1839
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001840 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001841
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001842 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001843 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1844 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001845 ++trace->stats.vfs_getname;
1846 }
1847
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001848 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001849 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001850 if (trace__filter_duration(trace, duration))
1851 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001852 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001853 } else if (trace->duration_filter)
1854 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001855
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001856 if (sample->callchain) {
1857 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1858 if (callchain_ret == 0) {
1859 if (callchain_cursor.nr < trace->min_stack)
1860 goto out;
1861 callchain_ret = 1;
1862 }
1863 }
1864
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001865 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001866 goto out;
1867
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001868 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001869
1870 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001871 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001872 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001873 fprintf(trace->output, " ... [");
1874 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1875 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001876 }
1877
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001878 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001879 if (ret < 0)
1880 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001881signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001882 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001883 } else if (ret < 0) {
1884errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001885 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001886 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001887 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001888
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001889 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001890 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001891 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001892 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001893 else if (ttrace->ret_scnprintf) {
1894 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001895 struct syscall_arg arg = {
1896 .val = ret,
1897 .thread = thread,
1898 .trace = trace,
1899 };
1900 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001901 ttrace->ret_scnprintf = NULL;
1902 fprintf(trace->output, ") = %s", bf);
1903 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001904 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001905 else if (sc->fmt->errpid) {
1906 struct thread *child = machine__find_thread(trace->host, ret, ret);
1907
1908 if (child != NULL) {
1909 fprintf(trace->output, ") = %ld", ret);
1910 if (child->comm_set)
1911 fprintf(trace->output, " (%s)", thread__comm_str(child));
1912 thread__put(child);
1913 }
1914 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001915 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001916
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001917 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001918
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001919 if (callchain_ret > 0)
1920 trace__fprintf_callchain(trace, sample);
1921 else if (callchain_ret < 0)
1922 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001923out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001924 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001925 err = 0;
1926out_put:
1927 thread__put(thread);
1928 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001929}
1930
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001931static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001932 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001933 struct perf_sample *sample)
1934{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001935 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1936 struct thread_trace *ttrace;
1937 size_t filename_len, entry_str_len, to_move;
1938 ssize_t remaining_space;
1939 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001940 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001941
1942 if (!thread)
1943 goto out;
1944
1945 ttrace = thread__priv(thread);
1946 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001947 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001948
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001949 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001950 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001951 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001952
1953 if (ttrace->filename.namelen < filename_len) {
1954 char *f = realloc(ttrace->filename.name, filename_len + 1);
1955
1956 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001957 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001958
1959 ttrace->filename.namelen = filename_len;
1960 ttrace->filename.name = f;
1961 }
1962
1963 strcpy(ttrace->filename.name, filename);
1964 ttrace->filename.pending_open = true;
1965
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001966 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001967 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001968
1969 entry_str_len = strlen(ttrace->entry_str);
1970 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1971 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001972 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001973
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001974 if (filename_len > (size_t)remaining_space) {
1975 filename += filename_len - remaining_space;
1976 filename_len = remaining_space;
1977 }
1978
1979 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1980 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1981 memmove(pos + filename_len, pos, to_move);
1982 memcpy(pos, filename, filename_len);
1983
1984 ttrace->filename.ptr = 0;
1985 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001986out_put:
1987 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001988out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001989 return 0;
1990}
1991
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001992static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001993 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001994 struct perf_sample *sample)
1995{
1996 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1997 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001998 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001999 sample->pid,
2000 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002001 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002002
2003 if (ttrace == NULL)
2004 goto out_dump;
2005
2006 ttrace->runtime_ms += runtime_ms;
2007 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002008out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002009 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002010 return 0;
2011
2012out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002013 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002014 evsel->name,
2015 perf_evsel__strval(evsel, sample, "comm"),
2016 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2017 runtime,
2018 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002019 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002020}
2021
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002022static int bpf_output__printer(enum binary_printer_ops op,
2023 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00002024{
Wang Nan1d6c9402016-02-26 09:31:55 +00002025 unsigned char ch = (unsigned char)val;
2026
2027 switch (op) {
2028 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002029 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00002030 case BINARY_PRINT_DATA_BEGIN:
2031 case BINARY_PRINT_LINE_BEGIN:
2032 case BINARY_PRINT_ADDR:
2033 case BINARY_PRINT_NUM_DATA:
2034 case BINARY_PRINT_NUM_PAD:
2035 case BINARY_PRINT_SEP:
2036 case BINARY_PRINT_CHAR_PAD:
2037 case BINARY_PRINT_LINE_END:
2038 case BINARY_PRINT_DATA_END:
2039 default:
2040 break;
2041 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002042
2043 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00002044}
2045
2046static void bpf_output__fprintf(struct trace *trace,
2047 struct perf_sample *sample)
2048{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002049 binary__fprintf(sample->raw_data, sample->raw_size, 8,
2050 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00002051}
2052
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002053static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2054 union perf_event *event __maybe_unused,
2055 struct perf_sample *sample)
2056{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002057 int callchain_ret = 0;
2058
2059 if (sample->callchain) {
2060 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2061 if (callchain_ret == 0) {
2062 if (callchain_cursor.nr < trace->min_stack)
2063 goto out;
2064 callchain_ret = 1;
2065 }
2066 }
2067
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03002068 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002069 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002070
2071 if (trace->trace_syscalls)
2072 fprintf(trace->output, "( ): ");
2073
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002074 if (evsel == trace->syscalls.events.augmented) {
2075 int id = perf_evsel__sc_tp_uint(evsel, id, sample);
2076 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2077
2078 if (sc) {
2079 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2080
2081 if (thread) {
Arnaldo Carvalho de Meloc96f4ed2018-08-21 11:47:44 -03002082 trace__fprintf_comm_tid(trace, thread, trace->output);
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002083 fprintf(trace->output, "%s(", sc->name);
2084 trace__fprintf_sys_enter(trace, evsel, sample);
2085 fputc(')', trace->output);
2086 thread__put(thread);
2087 goto newline;
2088 }
2089 }
2090
2091 /*
2092 * XXX: Not having the associated syscall info or not finding/adding
2093 * the thread should never happen, but if it does...
2094 * fall thru and print it as a bpf_output event.
2095 */
2096 }
2097
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002098 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002099
Wang Nan1d6c9402016-02-26 09:31:55 +00002100 if (perf_evsel__is_bpf_output(evsel)) {
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002101 bpf_output__fprintf(trace, sample);
Wang Nan1d6c9402016-02-26 09:31:55 +00002102 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002103 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2104 trace__fprintf_sys_enter(trace, evsel, sample)) {
2105 event_format__fprintf(evsel->tp_format, sample->cpu,
2106 sample->raw_data, sample->raw_size,
2107 trace->output);
2108 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002109 }
2110
Arnaldo Carvalho de Melo1cdf6182018-08-21 11:44:23 -03002111newline:
Changbin Du51125a22018-03-13 18:40:01 +08002112 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002113
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002114 if (callchain_ret > 0)
2115 trace__fprintf_callchain(trace, sample);
2116 else if (callchain_ret < 0)
2117 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2118out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002119 return 0;
2120}
2121
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002122static void print_location(FILE *f, struct perf_sample *sample,
2123 struct addr_location *al,
2124 bool print_dso, bool print_sym)
2125{
2126
Namhyung Kimbb963e12017-02-17 17:17:38 +09002127 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002128 fprintf(f, "%s@", al->map->dso->long_name);
2129
Namhyung Kimbb963e12017-02-17 17:17:38 +09002130 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002131 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002132 al->addr - al->sym->start);
2133 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002134 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002135 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002136 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002137}
2138
2139static int trace__pgfault(struct trace *trace,
2140 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002141 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002142 struct perf_sample *sample)
2143{
2144 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002145 struct addr_location al;
2146 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002147 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002148 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002149 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002150
2151 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002152
2153 if (sample->callchain) {
2154 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2155 if (callchain_ret == 0) {
2156 if (callchain_cursor.nr < trace->min_stack)
2157 goto out_put;
2158 callchain_ret = 1;
2159 }
2160 }
2161
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002162 ttrace = thread__trace(thread, trace->output);
2163 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002164 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002165
2166 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2167 ttrace->pfmaj++;
2168 else
2169 ttrace->pfmin++;
2170
2171 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002172 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002173
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002174 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002175
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002176 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002177
2178 fprintf(trace->output, "%sfault [",
2179 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2180 "maj" : "min");
2181
2182 print_location(trace->output, sample, &al, false, true);
2183
2184 fprintf(trace->output, "] => ");
2185
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002186 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002187
2188 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002189 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002190
2191 if (al.map)
2192 map_type = 'x';
2193 else
2194 map_type = '?';
2195 }
2196
2197 print_location(trace->output, sample, &al, true, false);
2198
2199 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002200
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002201 if (callchain_ret > 0)
2202 trace__fprintf_callchain(trace, sample);
2203 else if (callchain_ret < 0)
2204 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002205out:
2206 err = 0;
2207out_put:
2208 thread__put(thread);
2209 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002210}
2211
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002212static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002213 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002214 struct perf_sample *sample)
2215{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002216 /*
2217 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2218 * and don't use sample->time unconditionally, we may end up having
2219 * some other event in the future without PERF_SAMPLE_TIME for good
2220 * reason, i.e. we may not be interested in its timestamps, just in
2221 * it taking place, picking some piece of information when it
2222 * appears in our event stream (vfs_getname comes to mind).
2223 */
2224 if (trace->base_time == 0 && !trace->full_time &&
2225 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002226 trace->base_time = sample->time;
2227}
2228
David Ahern6810fc92013-08-28 22:29:52 -06002229static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002230 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002231 struct perf_sample *sample,
2232 struct perf_evsel *evsel,
2233 struct machine *machine __maybe_unused)
2234{
2235 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002236 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002237 int err = 0;
2238
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002239 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002240
David Ahernaa07df62016-11-25 09:29:52 -07002241 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2242 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002243 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002244
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002245 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002246
David Ahern31605652013-12-04 19:41:41 -07002247 if (handler) {
2248 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002249 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002250 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002251out:
2252 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002253 return err;
2254}
2255
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002256static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002257{
2258 unsigned int rec_argc, i, j;
2259 const char **rec_argv;
2260 const char * const record_args[] = {
2261 "record",
2262 "-R",
2263 "-m", "1024",
2264 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002265 };
2266
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002267 const char * const sc_args[] = { "-e", };
2268 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2269 const char * const majpf_args[] = { "-e", "major-faults" };
2270 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2271 const char * const minpf_args[] = { "-e", "minor-faults" };
2272 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2273
David Ahern9aca7f12013-12-04 19:41:39 -07002274 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002275 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2276 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002277 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2278
2279 if (rec_argv == NULL)
2280 return -ENOMEM;
2281
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002282 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002283 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002284 rec_argv[j++] = record_args[i];
2285
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002286 if (trace->trace_syscalls) {
2287 for (i = 0; i < sc_args_nr; i++)
2288 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002289
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002290 /* event string may be different for older kernels - e.g., RHEL6 */
2291 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2292 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2293 else if (is_valid_tracepoint("syscalls:sys_enter"))
2294 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2295 else {
2296 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002297 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002298 return -1;
2299 }
David Ahern9aca7f12013-12-04 19:41:39 -07002300 }
David Ahern9aca7f12013-12-04 19:41:39 -07002301
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002302 if (trace->trace_pgfaults & TRACE_PFMAJ)
2303 for (i = 0; i < majpf_args_nr; i++)
2304 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002305
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002306 if (trace->trace_pgfaults & TRACE_PFMIN)
2307 for (i = 0; i < minpf_args_nr; i++)
2308 rec_argv[j++] = minpf_args[i];
2309
2310 for (i = 0; i < (unsigned int)argc; i++)
2311 rec_argv[j++] = argv[i];
2312
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002313 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002314}
2315
David Ahernbf2575c2013-10-08 21:26:53 -06002316static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2317
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002318static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002319{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002320 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002321
2322 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002323 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002324
2325 if (perf_evsel__field(evsel, "pathname") == NULL) {
2326 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002327 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002328 }
2329
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002330 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002331 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002332 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002333}
2334
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002335static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002336{
2337 struct perf_evsel *evsel;
2338 struct perf_event_attr attr = {
2339 .type = PERF_TYPE_SOFTWARE,
2340 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002341 };
2342
2343 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002344 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002345
2346 event_attr_init(&attr);
2347
2348 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002349 if (evsel)
2350 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002351
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002352 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002353}
2354
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002355static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2356{
2357 const u32 type = event->header.type;
2358 struct perf_evsel *evsel;
2359
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002360 if (type != PERF_RECORD_SAMPLE) {
2361 trace__process_event(trace, trace->host, event, sample);
2362 return;
2363 }
2364
2365 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2366 if (evsel == NULL) {
2367 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2368 return;
2369 }
2370
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002371 trace__set_base_time(trace, evsel, sample);
2372
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002373 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2374 sample->raw_data == NULL) {
2375 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2376 perf_evsel__name(evsel), sample->tid,
2377 sample->cpu, sample->raw_size);
2378 } else {
2379 tracepoint_handler handler = evsel->handler;
2380 handler(trace, evsel, event, sample);
2381 }
2382}
2383
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002384static int trace__add_syscall_newtp(struct trace *trace)
2385{
2386 int ret = -1;
2387 struct perf_evlist *evlist = trace->evlist;
2388 struct perf_evsel *sys_enter, *sys_exit;
2389
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002390 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002391 if (sys_enter == NULL)
2392 goto out;
2393
2394 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2395 goto out_delete_sys_enter;
2396
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002397 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002398 if (sys_exit == NULL)
2399 goto out_delete_sys_enter;
2400
2401 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2402 goto out_delete_sys_exit;
2403
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002404 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2405 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2406
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002407 perf_evlist__add(evlist, sys_enter);
2408 perf_evlist__add(evlist, sys_exit);
2409
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002410 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002411 /*
2412 * We're interested only in the user space callchain
2413 * leading to the syscall, allow overriding that for
2414 * debugging reasons using --kernel_syscall_callchains
2415 */
2416 sys_exit->attr.exclude_callchain_kernel = 1;
2417 }
2418
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002419 trace->syscalls.events.sys_enter = sys_enter;
2420 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002421
2422 ret = 0;
2423out:
2424 return ret;
2425
2426out_delete_sys_exit:
2427 perf_evsel__delete_priv(sys_exit);
2428out_delete_sys_enter:
2429 perf_evsel__delete_priv(sys_enter);
2430 goto out;
2431}
2432
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002433static int trace__set_ev_qualifier_filter(struct trace *trace)
2434{
2435 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002436 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002437 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2438 trace->ev_qualifier_ids.nr,
2439 trace->ev_qualifier_ids.entries);
2440
2441 if (filter == NULL)
2442 goto out_enomem;
2443
Mathieu Poirier3541c032016-09-16 08:44:04 -06002444 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2445 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002446 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002447 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002448 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002449
2450 free(filter);
2451out:
2452 return err;
2453out_enomem:
2454 errno = ENOMEM;
2455 goto out;
2456}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002457
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002458static int trace__set_filter_loop_pids(struct trace *trace)
2459{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002460 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002461 pid_t pids[32] = {
2462 getpid(),
2463 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002464 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2465
2466 while (thread && nr < ARRAY_SIZE(pids)) {
2467 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2468
2469 if (parent == NULL)
2470 break;
2471
2472 if (!strcmp(thread__comm_str(parent), "sshd")) {
2473 pids[nr++] = parent->tid;
2474 break;
2475 }
2476 thread = parent;
2477 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002478
2479 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2480}
2481
Namhyung Kimf15eb532012-10-05 14:02:16 +09002482static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002483{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002484 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002485 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002486 int err = -1, i;
2487 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002488 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002489 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002490
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002491 trace->live = true;
2492
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002493 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002494 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002495
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002496 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002497 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002498
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002499 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2500 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2501 if (pgfault_maj == NULL)
2502 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002503 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002504 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002505 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002506
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002507 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2508 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2509 if (pgfault_min == NULL)
2510 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002511 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002512 perf_evlist__add(evlist, pgfault_min);
2513 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002514
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002515 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002516 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2517 trace__sched_stat_runtime))
2518 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002519
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002520 /*
2521 * If a global cgroup was set, apply it to all the events without an
2522 * explicit cgroup. I.e.:
2523 *
2524 * trace -G A -e sched:*switch
2525 *
2526 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2527 * _and_ sched:sched_switch to the 'A' cgroup, while:
2528 *
2529 * trace -e sched:*switch -G A
2530 *
2531 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2532 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2533 * a cgroup (on the root cgroup, sys wide, etc).
2534 *
2535 * Multiple cgroups:
2536 *
2537 * trace -G A -e sched:*switch -G B
2538 *
2539 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2540 * to the 'B' cgroup.
2541 *
2542 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2543 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2544 */
2545 if (trace->cgroup)
2546 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2547
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002548 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2549 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002550 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002551 goto out_delete_evlist;
2552 }
2553
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002554 err = trace__symbols_init(trace, evlist);
2555 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002556 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002557 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002558 }
2559
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002560 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002561
Namhyung Kimf15eb532012-10-05 14:02:16 +09002562 signal(SIGCHLD, sig_handler);
2563 signal(SIGINT, sig_handler);
2564
2565 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002566 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002567 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002568 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002569 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002570 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002571 }
2572 }
2573
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002574 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002575 if (err < 0)
2576 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002577
Wang Nanba504232016-02-26 09:31:54 +00002578 err = bpf__apply_obj_config();
2579 if (err) {
2580 char errbuf[BUFSIZ];
2581
2582 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2583 pr_err("ERROR: Apply config to BPF failed: %s\n",
2584 errbuf);
2585 goto out_error_open;
2586 }
2587
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002588 /*
2589 * Better not use !target__has_task() here because we need to cover the
2590 * case where no threads were specified in the command line, but a
2591 * workload was, and in that case we will fill in the thread_map when
2592 * we fork the workload in perf_evlist__prepare_workload.
2593 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002594 if (trace->filter_pids.nr > 0)
2595 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002596 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002597 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002598
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002599 if (err < 0)
2600 goto out_error_mem;
2601
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002602 if (trace->ev_qualifier_ids.nr > 0) {
2603 err = trace__set_ev_qualifier_filter(trace);
2604 if (err < 0)
2605 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002606
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002607 pr_debug("event qualifier tracepoint filter: %s\n",
2608 trace->syscalls.events.sys_exit->filter);
2609 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002610
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002611 err = perf_evlist__apply_filters(evlist, &evsel);
2612 if (err < 0)
2613 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002614
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002615 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002616 if (err < 0)
2617 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002618
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002619 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002620 perf_evlist__enable(evlist);
2621
Namhyung Kimf15eb532012-10-05 14:02:16 +09002622 if (forks)
2623 perf_evlist__start_workload(evlist);
2624
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002625 if (trace->opts.initial_delay) {
2626 usleep(trace->opts.initial_delay * 1000);
2627 perf_evlist__enable(evlist);
2628 }
2629
Jiri Olsae13798c2015-06-23 00:36:02 +02002630 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002631 evlist->threads->nr > 1 ||
2632 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002633
2634 /*
2635 * Now that we already used evsel->attr to ask the kernel to setup the
2636 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2637 * trace__resolve_callchain(), allowing per-event max-stack settings
2638 * to override an explicitely set --max-stack global setting.
2639 */
2640 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002641 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002642 evsel->attr.sample_max_stack == 0)
2643 evsel->attr.sample_max_stack = trace->max_stack;
2644 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002645again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002646 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002647
2648 for (i = 0; i < evlist->nr_mmaps; i++) {
2649 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002650 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002651
Kan Liangd7f55c62018-03-01 18:08:59 -05002652 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002653 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002654 continue;
2655
Kan Liang0019dc872018-03-06 10:36:06 -05002656 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002657 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002658
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002659 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002660
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002661 err = perf_evlist__parse_sample(evlist, event, &sample);
2662 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002663 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002664 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002665 }
2666
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002667 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002668next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002669 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002670
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002671 if (interrupted)
2672 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002673
2674 if (done && !draining) {
2675 perf_evlist__disable(evlist);
2676 draining = true;
2677 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002678 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002679 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002680 }
2681
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002682 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002683 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002684
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002685 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2686 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2687 draining = true;
2688
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002689 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002690 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002691 } else {
2692 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002693 }
2694
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002695out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002696 thread__zput(trace->current);
2697
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002698 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002699
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002700 if (!err) {
2701 if (trace->summary)
2702 trace__fprintf_thread_summary(trace, trace->output);
2703
2704 if (trace->show_tool_stats) {
2705 fprintf(trace->output, "Stats:\n "
2706 " vfs_getname : %" PRIu64 "\n"
2707 " proc_getname: %" PRIu64 "\n",
2708 trace->stats.vfs_getname,
2709 trace->stats.proc_getname);
2710 }
2711 }
David Ahernbf2575c2013-10-08 21:26:53 -06002712
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002713out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002714 trace__symbols__exit(trace);
2715
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002716 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002717 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002718 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002719 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002720 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002721{
2722 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002723
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002724out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002725 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002726 goto out_error;
2727
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002728out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002729 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002730 goto out_error;
2731
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002732out_error_mmap:
2733 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2734 goto out_error;
2735
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002736out_error_open:
2737 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2738
2739out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002740 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302741 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002742
2743out_error_apply_filters:
2744 fprintf(trace->output,
2745 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2746 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002747 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002748 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002749}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002750out_error_mem:
2751 fprintf(trace->output, "Not enough memory to run!\n");
2752 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002753
2754out_errno:
2755 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2756 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002757}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002758
David Ahern6810fc92013-08-28 22:29:52 -06002759static int trace__replay(struct trace *trace)
2760{
2761 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002762 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002763 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002764 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002765 .file = {
2766 .path = input_name,
2767 },
2768 .mode = PERF_DATA_MODE_READ,
2769 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002770 };
David Ahern6810fc92013-08-28 22:29:52 -06002771 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002772 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002773 int err = -1;
2774
2775 trace->tool.sample = trace__process_sample;
2776 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002777 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002778 trace->tool.comm = perf_event__process_comm;
2779 trace->tool.exit = perf_event__process_exit;
2780 trace->tool.fork = perf_event__process_fork;
2781 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302782 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002783 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302784 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002785
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002786 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002787 trace->tool.ordering_requires_timestamps = true;
2788
2789 /* add tid to output */
2790 trace->multiple_threads = true;
2791
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002792 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002793 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002794 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002795
David Ahernaa07df62016-11-25 09:29:52 -07002796 if (trace->opts.target.pid)
2797 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2798
2799 if (trace->opts.target.tid)
2800 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2801
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002802 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002803 goto out;
2804
David Ahern8fb598e2013-09-28 13:13:00 -06002805 trace->host = &session->machines.host;
2806
David Ahern6810fc92013-08-28 22:29:52 -06002807 err = perf_session__set_tracepoints_handlers(session, handlers);
2808 if (err)
2809 goto out;
2810
Namhyung Kim003824e2013-11-12 15:25:00 +09002811 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2812 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002813 /* older kernels have syscalls tp versus raw_syscalls */
2814 if (evsel == NULL)
2815 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2816 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002817
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002818 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002819 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002820 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002821 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2822 goto out;
2823 }
2824
2825 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2826 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002827 if (evsel == NULL)
2828 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2829 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002830 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002831 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002832 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002833 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002834 goto out;
2835 }
2836
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002837 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002838 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2839 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2840 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2841 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2842 evsel->handler = trace__pgfault;
2843 }
2844
David Ahern6810fc92013-08-28 22:29:52 -06002845 setup_pager();
2846
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002847 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002848 if (err)
2849 pr_err("Failed to process events, error %d", err);
2850
David Ahernbf2575c2013-10-08 21:26:53 -06002851 else if (trace->summary)
2852 trace__fprintf_thread_summary(trace, trace->output);
2853
David Ahern6810fc92013-08-28 22:29:52 -06002854out:
2855 perf_session__delete(session);
2856
2857 return err;
2858}
2859
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002860static size_t trace__fprintf_threads_header(FILE *fp)
2861{
2862 size_t printed;
2863
Pekka Enberg99ff7152013-11-12 16:42:14 +02002864 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002865
2866 return printed;
2867}
2868
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002869DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2870 struct stats *stats;
2871 double msecs;
2872 int syscall;
2873)
2874{
2875 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2876 struct stats *stats = source->priv;
2877
2878 entry->syscall = source->i;
2879 entry->stats = stats;
2880 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2881}
2882
David Ahernbf2575c2013-10-08 21:26:53 -06002883static size_t thread__dump_stats(struct thread_trace *ttrace,
2884 struct trace *trace, FILE *fp)
2885{
David Ahernbf2575c2013-10-08 21:26:53 -06002886 size_t printed = 0;
2887 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002888 struct rb_node *nd;
2889 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002890
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002891 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002892 return 0;
2893
2894 printed += fprintf(fp, "\n");
2895
Milian Wolff834fd462015-08-06 11:24:29 +02002896 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2897 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2898 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002899
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002900 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002901 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002902 if (stats) {
2903 double min = (double)(stats->min) / NSEC_PER_MSEC;
2904 double max = (double)(stats->max) / NSEC_PER_MSEC;
2905 double avg = avg_stats(stats);
2906 double pct;
2907 u64 n = (u64) stats->n;
2908
2909 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2910 avg /= NSEC_PER_MSEC;
2911
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002912 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002913 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002914 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002915 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002916 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002917 }
David Ahernbf2575c2013-10-08 21:26:53 -06002918 }
2919
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002920 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002921 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002922
2923 return printed;
2924}
2925
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002926static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002927{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002928 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002929 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002930 double ratio;
2931
2932 if (ttrace == NULL)
2933 return 0;
2934
2935 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2936
Pekka Enberg15e65c62013-11-14 18:43:30 +02002937 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002938 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002939 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002940 if (ttrace->pfmaj)
2941 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2942 if (ttrace->pfmin)
2943 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002944 if (trace->sched)
2945 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2946 else if (fputc('\n', fp) != EOF)
2947 ++printed;
2948
David Ahernbf2575c2013-10-08 21:26:53 -06002949 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002950
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002951 return printed;
2952}
David Ahern896cbb52013-09-28 13:12:59 -06002953
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002954static unsigned long thread__nr_events(struct thread_trace *ttrace)
2955{
2956 return ttrace ? ttrace->nr_events : 0;
2957}
2958
2959DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2960 struct thread *thread;
2961)
2962{
2963 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002964}
2965
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002966static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2967{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002968 size_t printed = trace__fprintf_threads_header(fp);
2969 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002970 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002971
Kan Liang91e467b2017-09-10 19:23:14 -07002972 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2973 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2974
2975 if (threads == NULL) {
2976 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2977 return 0;
2978 }
2979
2980 resort_rb__for_each_entry(nd, threads)
2981 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2982
2983 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002984 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002985 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002986}
2987
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002988static int trace__set_duration(const struct option *opt, const char *str,
2989 int unset __maybe_unused)
2990{
2991 struct trace *trace = opt->value;
2992
2993 trace->duration_filter = atof(str);
2994 return 0;
2995}
2996
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002997static int trace__set_filter_pids(const struct option *opt, const char *str,
2998 int unset __maybe_unused)
2999{
3000 int ret = -1;
3001 size_t i;
3002 struct trace *trace = opt->value;
3003 /*
3004 * FIXME: introduce a intarray class, plain parse csv and create a
3005 * { int nr, int entries[] } struct...
3006 */
3007 struct intlist *list = intlist__new(str);
3008
3009 if (list == NULL)
3010 return -1;
3011
3012 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
3013 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
3014
3015 if (trace->filter_pids.entries == NULL)
3016 goto out;
3017
3018 trace->filter_pids.entries[0] = getpid();
3019
3020 for (i = 1; i < trace->filter_pids.nr; ++i)
3021 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
3022
3023 intlist__delete(list);
3024 ret = 0;
3025out:
3026 return ret;
3027}
3028
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003029static int trace__open_output(struct trace *trace, const char *filename)
3030{
3031 struct stat st;
3032
3033 if (!stat(filename, &st) && st.st_size) {
3034 char oldname[PATH_MAX];
3035
3036 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
3037 unlink(oldname);
3038 rename(filename, oldname);
3039 }
3040
3041 trace->output = fopen(filename, "w");
3042
3043 return trace->output == NULL ? -errno : 0;
3044}
3045
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003046static int parse_pagefaults(const struct option *opt, const char *str,
3047 int unset __maybe_unused)
3048{
3049 int *trace_pgfaults = opt->value;
3050
3051 if (strcmp(str, "all") == 0)
3052 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
3053 else if (strcmp(str, "maj") == 0)
3054 *trace_pgfaults |= TRACE_PFMAJ;
3055 else if (strcmp(str, "min") == 0)
3056 *trace_pgfaults |= TRACE_PFMIN;
3057 else
3058 return -1;
3059
3060 return 0;
3061}
3062
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003063static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3064{
3065 struct perf_evsel *evsel;
3066
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003067 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003068 evsel->handler = handler;
3069}
3070
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003071static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist)
3072{
3073 struct perf_evsel *evsel;
3074
3075 evlist__for_each_entry(evlist, evsel) {
3076 if (evsel->priv || !evsel->tp_format)
3077 continue;
3078
3079 if (strcmp(evsel->tp_format->system, "syscalls"))
3080 continue;
3081
3082 if (perf_evsel__init_syscall_tp(evsel))
3083 return -1;
3084
3085 if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
3086 struct syscall_tp *sc = evsel->priv;
3087
3088 if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
3089 return -1;
3090 } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
3091 struct syscall_tp *sc = evsel->priv;
3092
3093 if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
3094 return -1;
3095 }
3096 }
3097
3098 return 0;
3099}
3100
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003101/*
3102 * XXX: Hackish, just splitting the combined -e+--event (syscalls
3103 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
3104 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
3105 *
3106 * It'd be better to introduce a parse_options() variant that would return a
3107 * list with the terms it didn't match to an event...
3108 */
3109static int trace__parse_events_option(const struct option *opt, const char *str,
3110 int unset __maybe_unused)
3111{
3112 struct trace *trace = (struct trace *)opt->value;
3113 const char *s = str;
3114 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003115 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003116 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
3117 char group_name[PATH_MAX];
3118
3119 if (strace_groups_dir == NULL)
3120 return -1;
3121
3122 if (*s == '!') {
3123 ++s;
3124 trace->not_ev_qualifier = true;
3125 }
3126
3127 while (1) {
3128 if ((sep = strchr(s, ',')) != NULL)
3129 *sep = '\0';
3130
3131 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003132 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3133 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003134 list = 1;
3135 } else {
3136 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3137 if (access(group_name, R_OK) == 0)
3138 list = 1;
3139 }
3140
3141 if (lists[list]) {
3142 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3143 } else {
3144 lists[list] = malloc(len);
3145 if (lists[list] == NULL)
3146 goto out;
3147 strcpy(lists[list], s);
3148 }
3149
3150 if (!sep)
3151 break;
3152
3153 *sep = ',';
3154 s = sep + 1;
3155 }
3156
3157 if (lists[1] != NULL) {
3158 struct strlist_config slist_config = {
3159 .dirname = strace_groups_dir,
3160 };
3161
3162 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3163 if (trace->ev_qualifier == NULL) {
3164 fputs("Not enough memory to parse event qualifier", trace->output);
3165 goto out;
3166 }
3167
3168 if (trace__validate_ev_qualifier(trace))
3169 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003170 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003171 }
3172
3173 err = 0;
3174
3175 if (lists[0]) {
3176 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3177 "event selector. use 'perf list' to list available events",
3178 parse_events_option);
3179 err = parse_events_option(&o, lists[0], 0);
3180 }
3181out:
3182 if (sep)
3183 *sep = ',';
3184
3185 return err;
3186}
3187
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003188static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3189{
3190 struct trace *trace = opt->value;
3191
3192 if (!list_empty(&trace->evlist->entries))
3193 return parse_cgroups(opt, str, unset);
3194
3195 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3196
3197 return 0;
3198}
3199
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003200int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003201{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003202 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003203 "perf trace [<options>] [<command>]",
3204 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003205 "perf trace record [<options>] [<command>]",
3206 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003207 NULL
3208 };
3209 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003210 .syscalls = {
3211 . max = -1,
3212 },
3213 .opts = {
3214 .target = {
3215 .uid = UINT_MAX,
3216 .uses_mmap = true,
3217 },
3218 .user_freq = UINT_MAX,
3219 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003220 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003221 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003222 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003223 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003224 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003225 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003226 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003227 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003228 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003229 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003230 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003231 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003232 OPT_CALLBACK('e', "event", &trace, "event",
3233 "event/syscall selector. use 'perf list' to list available events",
3234 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003235 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3236 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003237 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003238 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3239 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003240 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003241 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003242 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3243 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003244 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003245 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003246 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3247 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003248 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003249 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003250 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003251 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003252 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003253 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003254 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3255 "number of mmap data pages",
3256 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003257 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003258 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003259 OPT_CALLBACK(0, "duration", &trace, "float",
3260 "show only events with duration > N.M ms",
3261 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003262 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003263 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003264 OPT_BOOLEAN('T', "time", &trace.full_time,
3265 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003266 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3267 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003268 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3269 "Show only syscall summary with statistics"),
3270 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3271 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003272 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3273 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003274 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003275 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003276 OPT_CALLBACK(0, "call-graph", &trace.opts,
3277 "record_mode[,record_size]", record_callchain_help,
3278 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003279 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3280 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003281 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3282 "Set the minimum stack depth when parsing the callchain, "
3283 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003284 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3285 "Set the maximum stack depth when parsing the callchain, "
3286 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003287 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003288 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3289 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003290 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3291 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003292 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3293 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003294 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3295 "ms to wait before starting measurement after program "
3296 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003297 OPT_END()
3298 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003299 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003300 bool mmap_pages_user_set = true;
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003301 struct perf_evsel *evsel;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003302 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003303 int err = -1;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003304 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003305
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003306 signal(SIGSEGV, sighandler_dump_stack);
3307 signal(SIGFPE, sighandler_dump_stack);
3308
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003309 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003310 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003311
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003312 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003313 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003314 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003315 goto out;
3316 }
3317
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003318 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3319 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003320
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003321 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3322 usage_with_options_msg(trace_usage, trace_options,
3323 "cgroup monitoring only available in system-wide mode");
3324 }
3325
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003326 evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__");
3327 if (IS_ERR(evsel)) {
3328 bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf));
Arnaldo Carvalho de Meloe0b6d2e2018-08-07 15:40:13 -03003329 pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf);
3330 goto out;
3331 }
3332
Arnaldo Carvalho de Melod3d1c4bdf52018-08-07 16:21:44 -03003333 if (evsel) {
3334 if (perf_evsel__init_augmented_syscall_tp(evsel) ||
3335 perf_evsel__init_augmented_syscall_tp_args(evsel))
3336 goto out;
3337 trace.syscalls.events.augmented = evsel;
3338 }
3339
Wang Nand7888572016-04-08 15:07:24 +00003340 err = bpf__setup_stdout(trace.evlist);
3341 if (err) {
3342 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3343 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3344 goto out;
3345 }
3346
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003347 err = -1;
3348
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003349 if (trace.trace_pgfaults) {
3350 trace.opts.sample_address = true;
3351 trace.opts.sample_time = true;
3352 }
3353
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003354 if (trace.opts.mmap_pages == UINT_MAX)
3355 mmap_pages_user_set = false;
3356
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003357 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003358 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003359 max_stack_user_set = false;
3360 }
3361
3362#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003363 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003364 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003365 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003366#endif
3367
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003368 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003369 if (!mmap_pages_user_set && geteuid() == 0)
3370 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3371
Milian Wolff566a0882016-04-08 13:34:15 +02003372 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003373 }
Milian Wolff566a0882016-04-08 13:34:15 +02003374
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003375 if (trace.evlist->nr_entries > 0) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003376 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003377 if (evlist__set_syscall_tp_fields(trace.evlist)) {
3378 perror("failed to set syscalls:* tracepoint fields");
3379 goto out;
3380 }
3381 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003382
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003383 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3384 return trace__record(&trace, argc-1, &argv[1]);
3385
3386 /* summary_only implies summary option, but don't overwrite summary if set */
3387 if (trace.summary_only)
3388 trace.summary = trace.summary_only;
3389
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003390 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3391 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003392 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003393 }
3394
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003395 if (output_name != NULL) {
3396 err = trace__open_output(&trace, output_name);
3397 if (err < 0) {
3398 perror("failed to create output file");
3399 goto out;
3400 }
3401 }
3402
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003403 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003404 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003405 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003406 fprintf(trace.output, "%s", bf);
3407 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003408 }
3409
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003410 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003411 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003412 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003413 fprintf(trace.output, "%s", bf);
3414 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003415 }
3416
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003417 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003418 trace.opts.target.system_wide = true;
3419
David Ahern6810fc92013-08-28 22:29:52 -06003420 if (input_name)
3421 err = trace__replay(&trace);
3422 else
3423 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003424
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003425out_close:
3426 if (output_name != NULL)
3427 fclose(trace.output);
3428out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003429 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003430}