blob: 22ab8e67c7600865d7fc7a884feba24f15bbe66b [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.
859 */
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300860struct syscall {
861 struct event_format *tp_format;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300862 int nr_args;
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -0300863 bool is_exit;
864 bool is_open;
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -0300865 struct format_field *args;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300866 const char *name;
867 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -0300868 struct syscall_arg_fmt *arg_fmt;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300869};
870
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300871/*
872 * We need to have this 'calculated' boolean because in some cases we really
873 * don't know what is the duration of a syscall, for instance, when we start
874 * a session and some threads are waiting for a syscall to finish, say 'poll',
875 * in which case all we can do is to print "( ? ) for duration and for the
876 * start timestamp.
877 */
878static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200879{
880 double duration = (double)t / NSEC_PER_MSEC;
881 size_t printed = fprintf(fp, "(");
882
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300883 if (!calculated)
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -0300884 printed += fprintf(fp, " ");
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -0300885 else if (duration >= 1.0)
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200886 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
887 else if (duration >= 0.01)
888 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
889 else
890 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300891 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200892}
893
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300894/**
895 * filename.ptr: The filename char pointer that will be vfs_getname'd
896 * filename.entry_str_pos: Where to insert the string translated from
897 * filename.ptr by the vfs_getname tracepoint/kprobe.
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300898 * ret_scnprintf: syscall args may set this to a different syscall return
899 * formatter, for instance, fcntl may return fds, file flags, etc.
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300900 */
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300901struct thread_trace {
902 u64 entry_time;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300903 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300904 unsigned long nr_events;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +0400905 unsigned long pfmaj, pfmin;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300906 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300907 double runtime_ms;
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300908 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300909 struct {
910 unsigned long ptr;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -0300911 short int entry_str_pos;
912 bool pending_open;
913 unsigned int namelen;
914 char *name;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -0300915 } filename;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300916 struct {
917 int max;
918 char **table;
919 } paths;
David Ahernbf2575c2013-10-08 21:26:53 -0600920
921 struct intlist *syscall_stats;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300922};
923
924static struct thread_trace *thread_trace__new(void)
925{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
927
928 if (ttrace)
929 ttrace->paths.max = -1;
930
David Ahernbf2575c2013-10-08 21:26:53 -0600931 ttrace->syscall_stats = intlist__new(NULL);
932
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300933 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300934}
935
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300936static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300937{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300938 struct thread_trace *ttrace;
939
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300940 if (thread == NULL)
941 goto fail;
942
Namhyung Kim89dceb22014-10-06 09:46:03 +0900943 if (thread__priv(thread) == NULL)
944 thread__set_priv(thread, thread_trace__new());
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300945
Namhyung Kim89dceb22014-10-06 09:46:03 +0900946 if (thread__priv(thread) == NULL)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300947 goto fail;
948
Namhyung Kim89dceb22014-10-06 09:46:03 +0900949 ttrace = thread__priv(thread);
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300950 ++ttrace->nr_events;
951
952 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300953fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300954 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300955 "WARNING: not enough memory, dropping samples!\n");
956 return NULL;
957}
958
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300959
960void syscall_arg__set_ret_scnprintf(struct syscall_arg *arg,
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -0300961 size_t (*ret_scnprintf)(char *bf, size_t size, struct syscall_arg *arg))
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -0300962{
963 struct thread_trace *ttrace = thread__priv(arg->thread);
964
965 ttrace->ret_scnprintf = ret_scnprintf;
966}
967
Stanislav Fomichev598d02c2014-06-26 20:14:25 +0400968#define TRACE_PFMAJ (1 << 0)
969#define TRACE_PFMIN (1 << 1)
970
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -0300971static const size_t trace__entry_str_size = 2048;
972
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300973static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300974{
Namhyung Kim89dceb22014-10-06 09:46:03 +0900975 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300976
977 if (fd > ttrace->paths.max) {
978 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
979
980 if (npath == NULL)
981 return -1;
982
983 if (ttrace->paths.max != -1) {
984 memset(npath + ttrace->paths.max + 1, 0,
985 (fd - ttrace->paths.max) * sizeof(char *));
986 } else {
987 memset(npath, 0, (fd + 1) * sizeof(char *));
988 }
989
990 ttrace->paths.table = npath;
991 ttrace->paths.max = fd;
992 }
993
994 ttrace->paths.table[fd] = strdup(pathname);
995
996 return ttrace->paths.table[fd] != NULL ? 0 : -1;
997}
998
Arnaldo Carvalho de Melo97119f32013-09-27 17:34:10 -0300999static int thread__read_fd_path(struct thread *thread, int fd)
1000{
1001 char linkname[PATH_MAX], pathname[PATH_MAX];
1002 struct stat st;
1003 int ret;
1004
1005 if (thread->pid_ == thread->tid) {
1006 scnprintf(linkname, sizeof(linkname),
1007 "/proc/%d/fd/%d", thread->pid_, fd);
1008 } else {
1009 scnprintf(linkname, sizeof(linkname),
1010 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1011 }
1012
1013 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1014 return -1;
1015
1016 ret = readlink(linkname, pathname, sizeof(pathname));
1017
1018 if (ret < 0 || ret > st.st_size)
1019 return -1;
1020
1021 pathname[ret] = '\0';
1022 return trace__set_fd_pathname(thread, fd, pathname);
1023}
1024
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001025static const char *thread__fd_path(struct thread *thread, int fd,
1026 struct trace *trace)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001027{
Namhyung Kim89dceb22014-10-06 09:46:03 +09001028 struct thread_trace *ttrace = thread__priv(thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001029
1030 if (ttrace == NULL)
1031 return NULL;
1032
1033 if (fd < 0)
1034 return NULL;
1035
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001036 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001037 if (!trace->live)
1038 return NULL;
1039 ++trace->stats.proc_getname;
Arnaldo Carvalho de Melocdcd1e62014-06-10 16:00:18 -03001040 if (thread__read_fd_path(thread, fd))
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001041 return NULL;
1042 }
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001043
1044 return ttrace->paths.table[fd];
1045}
1046
Arnaldo Carvalho de Melofc65eb82017-07-14 15:21:40 -03001047size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001048{
1049 int fd = arg->val;
1050 size_t printed = scnprintf(bf, size, "%d", fd);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001051 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001052
1053 if (path)
1054 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1055
1056 return printed;
1057}
1058
Arnaldo Carvalho de Melo0a2f75402017-10-31 11:30:09 -03001059size_t pid__scnprintf_fd(struct trace *trace, pid_t pid, int fd, char *bf, size_t size)
1060{
1061 size_t printed = scnprintf(bf, size, "%d", fd);
1062 struct thread *thread = machine__find_thread(trace->host, pid, pid);
1063
1064 if (thread) {
1065 const char *path = thread__fd_path(thread, fd, trace);
1066
1067 if (path)
1068 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1069
1070 thread__put(thread);
1071 }
1072
1073 return printed;
1074}
1075
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001076static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1077 struct syscall_arg *arg)
1078{
1079 int fd = arg->val;
1080 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
Namhyung Kim89dceb22014-10-06 09:46:03 +09001081 struct thread_trace *ttrace = thread__priv(arg->thread);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001082
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001083 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1084 zfree(&ttrace->paths.table[fd]);
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001085
1086 return printed;
1087}
1088
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001089static void thread__set_filename_pos(struct thread *thread, const char *bf,
1090 unsigned long ptr)
1091{
1092 struct thread_trace *ttrace = thread__priv(thread);
1093
1094 ttrace->filename.ptr = ptr;
1095 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1096}
1097
1098static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1099 struct syscall_arg *arg)
1100{
1101 unsigned long ptr = arg->val;
1102
1103 if (!arg->trace->vfs_getname)
1104 return scnprintf(bf, size, "%#x", ptr);
1105
1106 thread__set_filename_pos(arg->thread, bf, ptr);
1107 return 0;
1108}
1109
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001110static bool trace__filter_duration(struct trace *trace, double t)
1111{
1112 return t < (trace->duration_filter * NSEC_PER_MSEC);
1113}
1114
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001115static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001116{
1117 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1118
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001119 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001120}
1121
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001122/*
1123 * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are
1124 * using ttrace->entry_time for a thread that receives a sys_exit without
1125 * first having received a sys_enter ("poll" issued before tracing session
1126 * starts, lost sys_enter exit due to ring buffer overflow).
1127 */
1128static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1129{
1130 if (tstamp > 0)
1131 return __trace__fprintf_tstamp(trace, tstamp, fp);
1132
1133 return fprintf(fp, " ? ");
1134}
1135
Namhyung Kimf15eb532012-10-05 14:02:16 +09001136static bool done = false;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001137static bool interrupted = false;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001138
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001139static void sig_handler(int sig)
Namhyung Kimf15eb532012-10-05 14:02:16 +09001140{
1141 done = true;
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03001142 interrupted = sig == SIGINT;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001143}
1144
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001145static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001146 u64 duration, bool duration_calculated, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001147{
1148 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001149 printed += fprintf_duration(duration, duration_calculated, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001150
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001151 if (trace->multiple_threads) {
1152 if (trace->show_comm)
Frederic Weisbecker1902efe2013-09-11 16:56:44 +02001153 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
Adrian Hunter38051232013-07-04 16:20:31 +03001154 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001155 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001156
1157 return printed;
1158}
1159
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001160static int trace__process_event(struct trace *trace, struct machine *machine,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001161 union perf_event *event, struct perf_sample *sample)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001162{
1163 int ret = 0;
1164
1165 switch (event->header.type) {
1166 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001167 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001168 "LOST %" PRIu64 " events!\n", event->lost.lost);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001169 ret = machine__process_lost_event(machine, event, sample);
Arnaldo Carvalho de Melo3ed5ca22016-03-30 16:51:17 -03001170 break;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001171 default:
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001172 ret = machine__process_event(machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001173 break;
1174 }
1175
1176 return ret;
1177}
1178
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001179static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001180 union perf_event *event,
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001181 struct perf_sample *sample,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001182 struct machine *machine)
1183{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001184 struct trace *trace = container_of(tool, struct trace, tool);
Frederic Weisbecker162f0be2013-09-11 16:18:24 +02001185 return trace__process_event(trace, machine, event, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001186}
1187
Arnaldo Carvalho de Melocaf8a0d2016-05-17 11:56:24 -03001188static char *trace__machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp)
1189{
1190 struct machine *machine = vmachine;
1191
1192 if (machine->kptr_restrict_warned)
1193 return NULL;
1194
1195 if (symbol_conf.kptr_restrict) {
1196 pr_warning("Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
1197 "Check /proc/sys/kernel/kptr_restrict.\n\n"
1198 "Kernel samples will not be resolved.\n");
1199 machine->kptr_restrict_warned = true;
1200 return NULL;
1201 }
1202
1203 return machine__resolve_kernel_addr(vmachine, addrp, modp);
1204}
1205
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001206static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1207{
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09001208 int err = symbol__init(NULL);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001209
1210 if (err)
1211 return err;
1212
David Ahern8fb598e2013-09-28 13:13:00 -06001213 trace->host = machine__new_host();
1214 if (trace->host == NULL)
1215 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001216
Andrei Vagincbd5c172017-11-07 16:22:46 -08001217 err = trace_event__register_resolver(trace->host, trace__machine__resolve_kernel_addr);
1218 if (err < 0)
1219 goto out;
Arnaldo Carvalho de Melo706c3da2015-07-22 16:16:16 -03001220
Arnaldo Carvalho de Meloa33fbd52013-11-11 11:36:12 -03001221 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
Kan Liang9d9cad72015-06-17 09:51:11 -04001222 evlist->threads, trace__tool_process, false,
Kan Liang340b47f2017-09-29 07:47:54 -07001223 trace->opts.proc_map_timeout, 1);
Andrei Vagincbd5c172017-11-07 16:22:46 -08001224out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001225 if (err)
1226 symbol__exit();
1227
1228 return err;
1229}
1230
Andrei Vagin33974a42017-11-07 16:22:45 -08001231static void trace__symbols__exit(struct trace *trace)
1232{
1233 machine__exit(trace->host);
1234 trace->host = NULL;
1235
1236 symbol__exit();
1237}
1238
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001239static int syscall__alloc_arg_fmts(struct syscall *sc, int nr_args)
1240{
1241 int idx;
1242
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001243 if (nr_args == 6 && sc->fmt && sc->fmt->nr_args != 0)
1244 nr_args = sc->fmt->nr_args;
1245
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001246 sc->arg_fmt = calloc(nr_args, sizeof(*sc->arg_fmt));
1247 if (sc->arg_fmt == NULL)
1248 return -1;
1249
1250 for (idx = 0; idx < nr_args; ++idx) {
1251 if (sc->fmt)
1252 sc->arg_fmt[idx] = sc->fmt->arg[idx];
1253 }
1254
1255 sc->nr_args = nr_args;
1256 return 0;
1257}
1258
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001259static int syscall__set_arg_fmts(struct syscall *sc)
1260{
1261 struct format_field *field;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001262 int idx = 0, len;
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001263
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001264 for (field = sc->args; field; field = field->next, ++idx) {
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001265 if (sc->fmt && sc->fmt->arg[idx].scnprintf)
1266 continue;
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001267
1268 if (strcmp(field->type, "const char *") == 0 &&
Arnaldo Carvalho de Melo12f3ca42016-05-23 16:37:55 -03001269 (strcmp(field->name, "filename") == 0 ||
1270 strcmp(field->name, "path") == 0 ||
1271 strcmp(field->name, "pathname") == 0))
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001272 sc->arg_fmt[idx].scnprintf = SCA_FILENAME;
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001273 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001274 sc->arg_fmt[idx].scnprintf = syscall_arg__scnprintf_hex;
Arnaldo Carvalho de Melod1d438a2016-04-06 18:02:41 -03001275 else if (strcmp(field->type, "pid_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001276 sc->arg_fmt[idx].scnprintf = SCA_PID;
Arnaldo Carvalho de Meloba2f22c2016-04-07 12:05:51 -03001277 else if (strcmp(field->type, "umode_t") == 0)
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001278 sc->arg_fmt[idx].scnprintf = SCA_MODE_T;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001279 else if ((strcmp(field->type, "int") == 0 ||
1280 strcmp(field->type, "unsigned int") == 0 ||
1281 strcmp(field->type, "long") == 0) &&
1282 (len = strlen(field->name)) >= 2 &&
1283 strcmp(field->name + len - 2, "fd") == 0) {
1284 /*
1285 * /sys/kernel/tracing/events/syscalls/sys_enter*
1286 * egrep 'field:.*fd;' .../format|sed -r 's/.*field:([a-z ]+) [a-z_]*fd.+/\1/g'|sort|uniq -c
1287 * 65 int
1288 * 23 unsigned int
1289 * 7 unsigned long
1290 */
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001291 sc->arg_fmt[idx].scnprintf = SCA_FD;
Arnaldo Carvalho de Melob6565c92016-05-23 12:59:53 -03001292 }
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001293 }
1294
1295 return 0;
1296}
1297
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001298static int trace__read_syscall_info(struct trace *trace, int id)
1299{
1300 char tp_name[128];
1301 struct syscall *sc;
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03001302 const char *name = syscalltbl__name(trace->sctbl, id);
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001303
1304 if (name == NULL)
1305 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001306
1307 if (id > trace->syscalls.max) {
1308 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1309
1310 if (nsyscalls == NULL)
1311 return -1;
1312
1313 if (trace->syscalls.max != -1) {
1314 memset(nsyscalls + trace->syscalls.max + 1, 0,
1315 (id - trace->syscalls.max) * sizeof(*sc));
1316 } else {
1317 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1318 }
1319
1320 trace->syscalls.table = nsyscalls;
1321 trace->syscalls.max = id;
1322 }
1323
1324 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001325 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001326
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001327 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001328
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001329 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
Jiri Olsa97978b32013-12-03 14:09:24 +01001330 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001331
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001332 if (IS_ERR(sc->tp_format) && sc->fmt && sc->fmt->alias) {
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001333 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
Jiri Olsa97978b32013-12-03 14:09:24 +01001334 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001335 }
1336
Arnaldo Carvalho de Melo5e58fcf2017-07-19 14:32:11 -03001337 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 6 : sc->tp_format->format.nr_fields))
1338 return -1;
1339
Jiri Olsa8dd2a132015-09-07 10:38:06 +02001340 if (IS_ERR(sc->tp_format))
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001341 return -1;
1342
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001343 sc->args = sc->tp_format->format.fields;
Taeung Songc42de702016-02-26 22:14:25 +09001344 /*
1345 * We need to check and discard the first variable '__syscall_nr'
1346 * or 'nr' that mean the syscall number. It is needless here.
1347 * So drop '__syscall_nr' or 'nr' field but does not exist on older kernels.
1348 */
1349 if (sc->args && (!strcmp(sc->args->name, "__syscall_nr") || !strcmp(sc->args->name, "nr"))) {
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001350 sc->args = sc->args->next;
1351 --sc->nr_args;
1352 }
1353
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001354 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001355 sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat");
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001356
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001357 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001358}
1359
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001360static int trace__validate_ev_qualifier(struct trace *trace)
1361{
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001362 int err = 0, i;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001363 size_t nr_allocated;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001364 struct str_node *pos;
1365
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001366 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1367 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1368 sizeof(trace->ev_qualifier_ids.entries[0]));
1369
1370 if (trace->ev_qualifier_ids.entries == NULL) {
1371 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1372 trace->output);
1373 err = -EINVAL;
1374 goto out;
1375 }
1376
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001377 nr_allocated = trace->ev_qualifier_ids.nr;
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001378 i = 0;
1379
Arnaldo Carvalho de Melo602a1f42016-06-23 11:31:20 -03001380 strlist__for_each_entry(pos, trace->ev_qualifier) {
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001381 const char *sc = pos->s;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001382 int id = syscalltbl__id(trace->sctbl, sc), match_next = -1;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001383
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001384 if (id < 0) {
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001385 id = syscalltbl__strglobmatch_first(trace->sctbl, sc, &match_next);
1386 if (id >= 0)
1387 goto matches;
1388
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001389 if (err == 0) {
1390 fputs("Error:\tInvalid syscall ", trace->output);
1391 err = -EINVAL;
1392 } else {
1393 fputs(", ", trace->output);
1394 }
1395
1396 fputs(sc, trace->output);
1397 }
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001398matches:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001399 trace->ev_qualifier_ids.entries[i++] = id;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001400 if (match_next == -1)
1401 continue;
1402
1403 while (1) {
1404 id = syscalltbl__strglobmatch_next(trace->sctbl, sc, &match_next);
1405 if (id < 0)
1406 break;
1407 if (nr_allocated == trace->ev_qualifier_ids.nr) {
1408 void *entries;
1409
1410 nr_allocated += 8;
1411 entries = realloc(trace->ev_qualifier_ids.entries,
1412 nr_allocated * sizeof(trace->ev_qualifier_ids.entries[0]));
1413 if (entries == NULL) {
1414 err = -ENOMEM;
1415 fputs("\nError:\t Not enough memory for parsing\n", trace->output);
1416 goto out_free;
1417 }
1418 trace->ev_qualifier_ids.entries = entries;
1419 }
1420 trace->ev_qualifier_ids.nr++;
1421 trace->ev_qualifier_ids.entries[i++] = id;
1422 }
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001423 }
1424
1425 if (err < 0) {
1426 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1427 "\nHint:\tand: 'man syscalls'\n", trace->output);
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03001428out_free:
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001429 zfree(&trace->ev_qualifier_ids.entries);
1430 trace->ev_qualifier_ids.nr = 0;
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001431 }
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03001432out:
Arnaldo Carvalho de Melod0cc4392015-06-25 19:32:33 -03001433 return err;
1434}
1435
David Ahern55d43bca2015-02-19 15:00:22 -05001436/*
1437 * args is to be interpreted as a series of longs but we need to handle
1438 * 8-byte unaligned accesses. args points to raw_data within the event
1439 * and raw_data is guaranteed to be 8-byte unaligned because it is
1440 * preceded by raw_size which is a u32. So we need to copy args to a temp
1441 * variable to read it. Most notably this avoids extended load instructions
1442 * on unaligned addresses
1443 */
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001444unsigned long syscall_arg__val(struct syscall_arg *arg, u8 idx)
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001445{
1446 unsigned long val;
Arnaldo Carvalho de Melo325f5092017-07-19 15:02:43 -03001447 unsigned char *p = arg->args + sizeof(unsigned long) * idx;
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001448
1449 memcpy(&val, p, sizeof(val));
1450 return val;
1451}
1452
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001453static size_t syscall__scnprintf_name(struct syscall *sc, char *bf, size_t size,
1454 struct syscall_arg *arg)
1455{
1456 if (sc->arg_fmt && sc->arg_fmt[arg->idx].name)
1457 return scnprintf(bf, size, "%s: ", sc->arg_fmt[arg->idx].name);
1458
1459 return scnprintf(bf, size, "arg%d: ", arg->idx);
1460}
1461
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001462static size_t syscall__scnprintf_val(struct syscall *sc, char *bf, size_t size,
1463 struct syscall_arg *arg, unsigned long val)
1464{
1465 if (sc->arg_fmt && sc->arg_fmt[arg->idx].scnprintf) {
1466 arg->val = val;
1467 if (sc->arg_fmt[arg->idx].parm)
1468 arg->parm = sc->arg_fmt[arg->idx].parm;
1469 return sc->arg_fmt[arg->idx].scnprintf(bf, size, arg);
1470 }
1471 return scnprintf(bf, size, "%ld", val);
1472}
1473
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001474static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
David Ahern55d43bca2015-02-19 15:00:22 -05001475 unsigned char *args, struct trace *trace,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001476 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001477{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001478 size_t printed = 0;
David Ahern55d43bca2015-02-19 15:00:22 -05001479 unsigned long val;
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001480 u8 bit = 1;
1481 struct syscall_arg arg = {
1482 .args = args,
1483 .idx = 0,
1484 .mask = 0,
1485 .trace = trace,
1486 .thread = thread,
1487 };
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001488 struct thread_trace *ttrace = thread__priv(thread);
1489
1490 /*
1491 * Things like fcntl will set this in its 'cmd' formatter to pick the
1492 * right formatter for the return value (an fd? file flags?), which is
1493 * not needed for syscalls that always return a given type, say an fd.
1494 */
1495 ttrace->ret_scnprintf = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001496
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001497 if (sc->args != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001498 struct format_field *field;
1499
Arnaldo Carvalho de Melof208bd82015-03-20 17:46:53 -03001500 for (field = sc->args; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001501 field = field->next, ++arg.idx, bit <<= 1) {
1502 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001503 continue;
David Ahern55d43bca2015-02-19 15:00:22 -05001504
Arnaldo Carvalho de Melof9f83b32017-07-14 10:13:56 -03001505 val = syscall_arg__val(&arg, arg.idx);
David Ahern55d43bca2015-02-19 15:00:22 -05001506
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001507 /*
1508 * Suppress this argument if its value is zero and
1509 * and we don't have a string associated in an
1510 * strarray for it.
1511 */
David Ahern55d43bca2015-02-19 15:00:22 -05001512 if (val == 0 &&
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001513 !(sc->arg_fmt &&
Arnaldo Carvalho de Melod47737d2017-07-17 15:59:03 -03001514 (sc->arg_fmt[arg.idx].show_zero ||
1515 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAY ||
Arnaldo Carvalho de Melo82d4a112017-07-17 15:22:47 -03001516 sc->arg_fmt[arg.idx].scnprintf == SCA_STRARRAYS) &&
1517 sc->arg_fmt[arg.idx].parm))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001518 continue;
1519
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001520 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001521 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001522 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523 }
Arnaldo Carvalho de Melo4c4d6e52016-05-05 23:38:05 -03001524 } else if (IS_ERR(sc->tp_format)) {
1525 /*
1526 * If we managed to read the tracepoint /format file, then we
1527 * may end up not having any args, like with gettid(), so only
1528 * print the raw args when we didn't manage to read it.
1529 */
Arnaldo Carvalho de Melo332337d2017-07-19 15:08:14 -03001530 while (arg.idx < sc->nr_args) {
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001531 if (arg.mask & bit)
1532 goto next_arg;
1533 val = syscall_arg__val(&arg, arg.idx);
Arnaldo Carvalho de Meloc51bdfe2017-07-19 15:47:30 -03001534 if (printed)
1535 printed += scnprintf(bf + printed, size - printed, ", ");
1536 printed += syscall__scnprintf_name(sc, bf + printed, size - printed, &arg);
Arnaldo Carvalho de Melod032d792017-07-19 14:36:13 -03001537 printed += syscall__scnprintf_val(sc, bf + printed, size - printed, &arg, val);
1538next_arg:
1539 ++arg.idx;
1540 bit <<= 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001541 }
1542 }
1543
1544 return printed;
1545}
1546
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001547typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001548 union perf_event *event,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001549 struct perf_sample *sample);
1550
1551static struct syscall *trace__syscall_info(struct trace *trace,
David Ahernbf2575c2013-10-08 21:26:53 -06001552 struct perf_evsel *evsel, int id)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001553{
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001554
1555 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001556
1557 /*
1558 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1559 * before that, leaving at a higher verbosity level till that is
1560 * explained. Reproduced with plain ftrace with:
1561 *
1562 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1563 * grep "NR -1 " /t/trace_pipe
1564 *
1565 * After generating some load on the machine.
1566 */
1567 if (verbose > 1) {
1568 static u64 n;
1569 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1570 id, perf_evsel__name(evsel), ++n);
1571 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001572 return NULL;
1573 }
1574
1575 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1576 trace__read_syscall_info(trace, id))
1577 goto out_cant_read;
1578
1579 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1580 goto out_cant_read;
1581
1582 return &trace->syscalls.table[id];
1583
1584out_cant_read:
Namhyung Kimbb963e12017-02-17 17:17:38 +09001585 if (verbose > 0) {
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001586 fprintf(trace->output, "Problems reading syscall %d", id);
1587 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1588 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1589 fputs(" information\n", trace->output);
1590 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001591 return NULL;
1592}
1593
David Ahernbf2575c2013-10-08 21:26:53 -06001594static void thread__update_stats(struct thread_trace *ttrace,
1595 int id, struct perf_sample *sample)
1596{
1597 struct int_node *inode;
1598 struct stats *stats;
1599 u64 duration = 0;
1600
1601 inode = intlist__findnew(ttrace->syscall_stats, id);
1602 if (inode == NULL)
1603 return;
1604
1605 stats = inode->priv;
1606 if (stats == NULL) {
1607 stats = malloc(sizeof(struct stats));
1608 if (stats == NULL)
1609 return;
1610 init_stats(stats);
1611 inode->priv = stats;
1612 }
1613
1614 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1615 duration = sample->time - ttrace->entry_time;
1616
1617 update_stats(stats, duration);
1618}
1619
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001620static int trace__printf_interrupted_entry(struct trace *trace)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001621{
1622 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001623 size_t printed;
1624
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001625 if (trace->failure_only || trace->current == NULL)
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001626 return 0;
1627
1628 ttrace = thread__priv(trace->current);
1629
1630 if (!ttrace->entry_pending)
1631 return 0;
1632
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001633 printed = trace__fprintf_entry_head(trace, trace->current, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001634 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1635 ttrace->entry_pending = false;
1636
1637 return printed;
1638}
1639
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001640static int trace__fprintf_sample(struct trace *trace, struct perf_evsel *evsel,
1641 struct perf_sample *sample, struct thread *thread)
1642{
1643 int printed = 0;
1644
1645 if (trace->print_sample) {
1646 double ts = (double)sample->time / NSEC_PER_MSEC;
1647
1648 printed += fprintf(trace->output, "%22s %10.3f %s %d/%d [%d]\n",
1649 perf_evsel__name(evsel), ts,
1650 thread__comm_str(thread),
1651 sample->pid, sample->tid, sample->cpu);
1652 }
1653
1654 return printed;
1655}
1656
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001657static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001658 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001659 struct perf_sample *sample)
1660{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001661 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001662 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001663 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001664 struct thread *thread;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001665 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
David Ahernbf2575c2013-10-08 21:26:53 -06001666 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001667 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001668
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001669 if (sc == NULL)
1670 return -1;
1671
David Ahern8fb598e2013-09-28 13:13:00 -06001672 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001673 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001674 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001675 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001676
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001677 trace__fprintf_sample(trace, evsel, sample, thread);
1678
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001679 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001680
1681 if (ttrace->entry_str == NULL) {
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001682 ttrace->entry_str = malloc(trace__entry_str_size);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001683 if (!ttrace->entry_str)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001684 goto out_put;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001685 }
1686
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001687 if (!(trace->duration_filter || trace->summary_only || trace->min_stack))
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03001688 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Meloe5966632015-02-13 13:22:21 -03001689
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001690 ttrace->entry_time = sample->time;
1691 msg = ttrace->entry_str;
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001692 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001693
Arnaldo Carvalho de Meloe4d44e82015-08-04 22:17:29 -03001694 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001695 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001696
Arnaldo Carvalho de Melo5089f202014-06-17 14:29:24 -03001697 if (sc->is_exit) {
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001698 if (!(trace->duration_filter || trace->summary_only || trace->failure_only || trace->min_stack)) {
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001699 trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Meloc008f782016-05-17 12:13:54 -03001700 fprintf(trace->output, "%-70s)\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001701 }
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001702 } else {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001703 ttrace->entry_pending = true;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001704 /* See trace__vfs_getname & trace__sys_exit */
1705 ttrace->filename.pending_open = false;
1706 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001707
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03001708 if (trace->current != thread) {
1709 thread__put(trace->current);
1710 trace->current = thread__get(thread);
1711 }
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001712 err = 0;
1713out_put:
1714 thread__put(thread);
1715 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001716}
1717
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001718static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel,
1719 struct perf_sample *sample)
1720{
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001721 struct thread_trace *ttrace;
1722 struct thread *thread;
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001723 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
1724 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001725 char msg[1024];
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001726 void *args;
1727
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001728 if (sc == NULL)
1729 return -1;
1730
1731 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1732 ttrace = thread__trace(thread, trace->output);
1733 /*
1734 * We need to get ttrace just to make sure it is there when syscall__scnprintf_args()
1735 * and the rest of the beautifiers accessing it via struct syscall_arg touches it.
1736 */
1737 if (ttrace == NULL)
1738 goto out_put;
1739
Arnaldo Carvalho de Melof3acd882018-08-02 15:11:58 -03001740 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03001741 syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread);
1742 fprintf(trace->output, "%s", msg);
1743 err = 0;
1744out_put:
1745 thread__put(thread);
1746 return err;
1747}
1748
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001749static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel,
1750 struct perf_sample *sample,
1751 struct callchain_cursor *cursor)
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001752{
1753 struct addr_location al;
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301754 int max_stack = evsel->attr.sample_max_stack ?
1755 evsel->attr.sample_max_stack :
1756 trace->max_stack;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001757
1758 if (machine__resolve(trace->host, &al, sample) < 0 ||
Ravi Bangoria3a9e9a42018-01-30 11:00:53 +05301759 thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, max_stack))
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001760 return -1;
1761
1762 return 0;
1763}
1764
1765static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample)
1766{
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001767 /* TODO: user-configurable print_opts */
Arnaldo Carvalho de Meloe20ab862016-04-12 15:16:15 -03001768 const unsigned int print_opts = EVSEL__PRINT_SYM |
1769 EVSEL__PRINT_DSO |
1770 EVSEL__PRINT_UNKNOWN_AS_ADDR;
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001771
Arnaldo Carvalho de Melod327e602016-04-14 17:53:49 -03001772 return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output);
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03001773}
1774
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001775static const char *errno_to_name(struct perf_evsel *evsel, int err)
1776{
1777 struct perf_env *env = perf_evsel__env(evsel);
1778 const char *arch_name = perf_env__arch(env);
1779
1780 return arch_syscalls__strerrno(arch_name, err);
1781}
1782
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001783static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001784 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001785 struct perf_sample *sample)
1786{
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001787 long ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001788 u64 duration = 0;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001789 bool duration_calculated = false;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001790 struct thread *thread;
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001791 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0;
David Ahernbf2575c2013-10-08 21:26:53 -06001792 struct syscall *sc = trace__syscall_info(trace, evsel, id);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001793 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001794
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001795 if (sc == NULL)
1796 return -1;
1797
David Ahern8fb598e2013-09-28 13:13:00 -06001798 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001799 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001800 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001801 goto out_put;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001802
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03001803 trace__fprintf_sample(trace, evsel, sample, thread);
1804
David Ahernbf2575c2013-10-08 21:26:53 -06001805 if (trace->summary)
1806 thread__update_stats(ttrace, id, sample);
1807
Arnaldo Carvalho de Melo77170982013-11-06 16:35:57 -03001808 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001809
Arnaldo Carvalho de Melo6a648b52018-08-02 10:30:08 -03001810 if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) {
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001811 trace__set_fd_pathname(thread, ret, ttrace->filename.name);
1812 ttrace->filename.pending_open = false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001813 ++trace->stats.vfs_getname;
1814 }
1815
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001816 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001817 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001818 if (trace__filter_duration(trace, duration))
1819 goto out;
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001820 duration_calculated = true;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001821 } else if (trace->duration_filter)
1822 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001823
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001824 if (sample->callchain) {
1825 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
1826 if (callchain_ret == 0) {
1827 if (callchain_cursor.nr < trace->min_stack)
1828 goto out;
1829 callchain_ret = 1;
1830 }
1831 }
1832
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03001833 if (trace->summary_only || (ret >= 0 && trace->failure_only))
David Ahernfd2eaba2013-11-12 09:31:15 -07001834 goto out;
1835
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03001836 trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001837
1838 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001839 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001840 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001841 fprintf(trace->output, " ... [");
1842 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1843 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001844 }
1845
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001846 if (sc->fmt == NULL) {
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001847 if (ret < 0)
1848 goto errno_print;
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001849signed_print:
Arnaldo Carvalho de Melo6f8fe612017-07-19 11:39:47 -03001850 fprintf(trace->output, ") = %ld", ret);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001851 } else if (ret < 0) {
1852errno_print: {
Masami Hiramatsu942a91e2014-08-14 02:22:41 +00001853 char bf[STRERR_BUFSIZE];
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03001854 const char *emsg = str_error_r(-ret, bf, sizeof(bf)),
Hendrik Brueckner092bd3c2018-01-19 09:56:16 +01001855 *e = errno_to_name(evsel, -ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001856
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001857 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Melo1f631392017-07-18 12:45:57 -03001858 }
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001859 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001860 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001861 else if (ttrace->ret_scnprintf) {
1862 char bf[1024];
Arnaldo Carvalho de Melo7ee57432017-07-14 15:16:54 -03001863 struct syscall_arg arg = {
1864 .val = ret,
1865 .thread = thread,
1866 .trace = trace,
1867 };
1868 ttrace->ret_scnprintf(bf, sizeof(bf), &arg);
Arnaldo Carvalho de Melo84486ca2017-07-14 11:35:03 -03001869 ttrace->ret_scnprintf = NULL;
1870 fprintf(trace->output, ") = %s", bf);
1871 } else if (sc->fmt->hexret)
Chang Hyun Park2c82c3a2014-09-26 21:54:01 +09001872 fprintf(trace->output, ") = %#lx", ret);
Arnaldo Carvalho de Melo11c8e392016-04-06 14:33:07 -03001873 else if (sc->fmt->errpid) {
1874 struct thread *child = machine__find_thread(trace->host, ret, ret);
1875
1876 if (child != NULL) {
1877 fprintf(trace->output, ") = %ld", ret);
1878 if (child->comm_set)
1879 fprintf(trace->output, " (%s)", thread__comm_str(child));
1880 thread__put(child);
1881 }
1882 } else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001883 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001884
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001885 fputc('\n', trace->output);
Milian Wolff566a0882016-04-08 13:34:15 +02001886
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03001887 if (callchain_ret > 0)
1888 trace__fprintf_callchain(trace, sample);
1889 else if (callchain_ret < 0)
1890 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001891out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001892 ttrace->entry_pending = false;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001893 err = 0;
1894out_put:
1895 thread__put(thread);
1896 return err;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001897}
1898
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001899static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001900 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001901 struct perf_sample *sample)
1902{
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001903 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
1904 struct thread_trace *ttrace;
1905 size_t filename_len, entry_str_len, to_move;
1906 ssize_t remaining_space;
1907 char *pos;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001908 const char *filename = perf_evsel__rawptr(evsel, sample, "pathname");
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001909
1910 if (!thread)
1911 goto out;
1912
1913 ttrace = thread__priv(thread);
1914 if (!ttrace)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001915 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001916
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001917 filename_len = strlen(filename);
Arnaldo Carvalho de Melo39f0e7a2017-03-24 14:51:28 -03001918 if (filename_len == 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001919 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001920
1921 if (ttrace->filename.namelen < filename_len) {
1922 char *f = realloc(ttrace->filename.name, filename_len + 1);
1923
1924 if (f == NULL)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001925 goto out_put;
Arnaldo Carvalho de Melo7f4f8002015-08-14 13:16:27 -03001926
1927 ttrace->filename.namelen = filename_len;
1928 ttrace->filename.name = f;
1929 }
1930
1931 strcpy(ttrace->filename.name, filename);
1932 ttrace->filename.pending_open = true;
1933
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001934 if (!ttrace->filename.ptr)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001935 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001936
1937 entry_str_len = strlen(ttrace->entry_str);
1938 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
1939 if (remaining_space <= 0)
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001940 goto out_put;
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001941
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001942 if (filename_len > (size_t)remaining_space) {
1943 filename += filename_len - remaining_space;
1944 filename_len = remaining_space;
1945 }
1946
1947 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
1948 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
1949 memmove(pos + filename_len, pos, to_move);
1950 memcpy(pos, filename, filename_len);
1951
1952 ttrace->filename.ptr = 0;
1953 ttrace->filename.entry_str_pos = 0;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001954out_put:
1955 thread__put(thread);
Arnaldo Carvalho de Melof9945922015-08-04 22:30:09 -03001956out:
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03001957 return 0;
1958}
1959
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001960static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04001961 union perf_event *event __maybe_unused,
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001962 struct perf_sample *sample)
1963{
1964 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1965 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001966 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001967 sample->pid,
1968 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001969 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001970
1971 if (ttrace == NULL)
1972 goto out_dump;
1973
1974 ttrace->runtime_ms += runtime_ms;
1975 trace->runtime_ms += runtime_ms;
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001976out_put:
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03001977 thread__put(thread);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001978 return 0;
1979
1980out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001981 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001982 evsel->name,
1983 perf_evsel__strval(evsel, sample, "comm"),
1984 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1985 runtime,
1986 perf_evsel__intval(evsel, sample, "vruntime"));
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03001987 goto out_put;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001988}
1989
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001990static int bpf_output__printer(enum binary_printer_ops op,
1991 unsigned int val, void *extra __maybe_unused, FILE *fp)
Wang Nan1d6c9402016-02-26 09:31:55 +00001992{
Wang Nan1d6c9402016-02-26 09:31:55 +00001993 unsigned char ch = (unsigned char)val;
1994
1995 switch (op) {
1996 case BINARY_PRINT_CHAR_DATA:
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03001997 return fprintf(fp, "%c", isprint(ch) ? ch : '.');
Wang Nan1d6c9402016-02-26 09:31:55 +00001998 case BINARY_PRINT_DATA_BEGIN:
1999 case BINARY_PRINT_LINE_BEGIN:
2000 case BINARY_PRINT_ADDR:
2001 case BINARY_PRINT_NUM_DATA:
2002 case BINARY_PRINT_NUM_PAD:
2003 case BINARY_PRINT_SEP:
2004 case BINARY_PRINT_CHAR_PAD:
2005 case BINARY_PRINT_LINE_END:
2006 case BINARY_PRINT_DATA_END:
2007 default:
2008 break;
2009 }
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002010
2011 return 0;
Wang Nan1d6c9402016-02-26 09:31:55 +00002012}
2013
2014static void bpf_output__fprintf(struct trace *trace,
2015 struct perf_sample *sample)
2016{
Arnaldo Carvalho de Melo923d0c92017-10-17 10:35:00 -03002017 binary__fprintf(sample->raw_data, sample->raw_size, 8,
2018 bpf_output__printer, NULL, trace->output);
Wang Nan1d6c9402016-02-26 09:31:55 +00002019}
2020
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002021static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2022 union perf_event *event __maybe_unused,
2023 struct perf_sample *sample)
2024{
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002025 int callchain_ret = 0;
2026
2027 if (sample->callchain) {
2028 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2029 if (callchain_ret == 0) {
2030 if (callchain_cursor.nr < trace->min_stack)
2031 goto out;
2032 callchain_ret = 1;
2033 }
2034 }
2035
Arnaldo Carvalho de Melo522283f2018-01-22 11:42:11 -03002036 trace__printf_interrupted_entry(trace);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002037 trace__fprintf_tstamp(trace, sample->time, trace->output);
Arnaldo Carvalho de Melo08089212015-02-19 21:51:50 -08002038
2039 if (trace->trace_syscalls)
2040 fprintf(trace->output, "( ): ");
2041
2042 fprintf(trace->output, "%s:", evsel->name);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002043
Wang Nan1d6c9402016-02-26 09:31:55 +00002044 if (perf_evsel__is_bpf_output(evsel)) {
Arnaldo Carvalho de Melo88cf7082018-08-07 16:26:35 -03002045 if (evsel == trace->syscalls.events.augmented)
2046 trace__fprintf_sys_enter(trace, evsel, sample);
2047 else
2048 bpf_output__fprintf(trace, sample);
Wang Nan1d6c9402016-02-26 09:31:55 +00002049 } else if (evsel->tp_format) {
Arnaldo Carvalho de Meloa98392b2018-08-02 14:05:09 -03002050 if (strncmp(evsel->tp_format->name, "sys_enter_", 10) ||
2051 trace__fprintf_sys_enter(trace, evsel, sample)) {
2052 event_format__fprintf(evsel->tp_format, sample->cpu,
2053 sample->raw_data, sample->raw_size,
2054 trace->output);
2055 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002056 }
2057
Changbin Du51125a22018-03-13 18:40:01 +08002058 fprintf(trace->output, "\n");
Arnaldo Carvalho de Melo202ff962016-04-12 10:11:07 -03002059
Arnaldo Carvalho de Melo7ad35612016-04-20 19:55:48 -03002060 if (callchain_ret > 0)
2061 trace__fprintf_callchain(trace, sample);
2062 else if (callchain_ret < 0)
2063 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
2064out:
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002065 return 0;
2066}
2067
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002068static void print_location(FILE *f, struct perf_sample *sample,
2069 struct addr_location *al,
2070 bool print_dso, bool print_sym)
2071{
2072
Namhyung Kimbb963e12017-02-17 17:17:38 +09002073 if ((verbose > 0 || print_dso) && al->map)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002074 fprintf(f, "%s@", al->map->dso->long_name);
2075
Namhyung Kimbb963e12017-02-17 17:17:38 +09002076 if ((verbose > 0 || print_sym) && al->sym)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002077 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002078 al->addr - al->sym->start);
2079 else if (al->map)
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002080 fprintf(f, "0x%" PRIx64, al->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002081 else
Arnaldo Carvalho de Melo4414a3c2014-07-08 15:39:21 -03002082 fprintf(f, "0x%" PRIx64, sample->addr);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002083}
2084
2085static int trace__pgfault(struct trace *trace,
2086 struct perf_evsel *evsel,
Arnaldo Carvalho de Melo473398a2016-03-22 18:23:43 -03002087 union perf_event *event __maybe_unused,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002088 struct perf_sample *sample)
2089{
2090 struct thread *thread;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002091 struct addr_location al;
2092 char map_type = 'd';
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002093 struct thread_trace *ttrace;
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002094 int err = -1;
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002095 int callchain_ret = 0;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002096
2097 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002098
2099 if (sample->callchain) {
2100 callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor);
2101 if (callchain_ret == 0) {
2102 if (callchain_cursor.nr < trace->min_stack)
2103 goto out_put;
2104 callchain_ret = 1;
2105 }
2106 }
2107
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002108 ttrace = thread__trace(thread, trace->output);
2109 if (ttrace == NULL)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002110 goto out_put;
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002111
2112 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2113 ttrace->pfmaj++;
2114 else
2115 ttrace->pfmin++;
2116
2117 if (trace->summary_only)
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002118 goto out;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002119
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002120 thread__find_symbol(thread, sample->cpumode, sample->ip, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002121
Arnaldo Carvalho de Melofd2b2972017-03-29 16:37:51 -03002122 trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002123
2124 fprintf(trace->output, "%sfault [",
2125 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2126 "maj" : "min");
2127
2128 print_location(trace->output, sample, &al, false, true);
2129
2130 fprintf(trace->output, "] => ");
2131
Arnaldo Carvalho de Melo117d3c22018-04-25 18:16:53 -03002132 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002133
2134 if (!al.map) {
Arnaldo Carvalho de Melo45462632018-04-24 11:24:49 -03002135 thread__find_symbol(thread, sample->cpumode, sample->addr, &al);
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002136
2137 if (al.map)
2138 map_type = 'x';
2139 else
2140 map_type = '?';
2141 }
2142
2143 print_location(trace->output, sample, &al, true, false);
2144
2145 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
Arnaldo Carvalho de Melo0c3a6ef2016-04-19 16:31:12 -03002146
Arnaldo Carvalho de Melo1df54292016-04-20 20:06:02 -03002147 if (callchain_ret > 0)
2148 trace__fprintf_callchain(trace, sample);
2149 else if (callchain_ret < 0)
2150 pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel));
Arnaldo Carvalho de Melob91fc392015-04-06 20:43:22 -03002151out:
2152 err = 0;
2153out_put:
2154 thread__put(thread);
2155 return err;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002156}
2157
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002158static void trace__set_base_time(struct trace *trace,
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002159 struct perf_evsel *evsel,
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002160 struct perf_sample *sample)
2161{
Arnaldo Carvalho de Melo8a07a802016-03-31 15:19:39 -03002162 /*
2163 * BPF events were not setting PERF_SAMPLE_TIME, so be more robust
2164 * and don't use sample->time unconditionally, we may end up having
2165 * some other event in the future without PERF_SAMPLE_TIME for good
2166 * reason, i.e. we may not be interested in its timestamps, just in
2167 * it taking place, picking some piece of information when it
2168 * appears in our event stream (vfs_getname comes to mind).
2169 */
2170 if (trace->base_time == 0 && !trace->full_time &&
2171 (evsel->attr.sample_type & PERF_SAMPLE_TIME))
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002172 trace->base_time = sample->time;
2173}
2174
David Ahern6810fc92013-08-28 22:29:52 -06002175static int trace__process_sample(struct perf_tool *tool,
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002176 union perf_event *event,
David Ahern6810fc92013-08-28 22:29:52 -06002177 struct perf_sample *sample,
2178 struct perf_evsel *evsel,
2179 struct machine *machine __maybe_unused)
2180{
2181 struct trace *trace = container_of(tool, struct trace, tool);
David Ahernaa07df62016-11-25 09:29:52 -07002182 struct thread *thread;
David Ahern6810fc92013-08-28 22:29:52 -06002183 int err = 0;
2184
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002185 tracepoint_handler handler = evsel->handler;
David Ahern6810fc92013-08-28 22:29:52 -06002186
David Ahernaa07df62016-11-25 09:29:52 -07002187 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2188 if (thread && thread__is_filtered(thread))
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002189 goto out;
David Ahernbdc89662013-08-28 22:29:53 -06002190
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002191 trace__set_base_time(trace, evsel, sample);
David Ahern6810fc92013-08-28 22:29:52 -06002192
David Ahern31605652013-12-04 19:41:41 -07002193 if (handler) {
2194 ++trace->nr_events;
Stanislav Fomichev0c82adc2014-06-26 20:14:24 +04002195 handler(trace, evsel, event, sample);
David Ahern31605652013-12-04 19:41:41 -07002196 }
Arnaldo Carvalho de Meloef65e962017-03-24 15:03:19 -03002197out:
2198 thread__put(thread);
David Ahern6810fc92013-08-28 22:29:52 -06002199 return err;
2200}
2201
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002202static int trace__record(struct trace *trace, int argc, const char **argv)
David Ahern5e2485b2013-09-28 13:13:01 -06002203{
2204 unsigned int rec_argc, i, j;
2205 const char **rec_argv;
2206 const char * const record_args[] = {
2207 "record",
2208 "-R",
2209 "-m", "1024",
2210 "-c", "1",
David Ahern5e2485b2013-09-28 13:13:01 -06002211 };
2212
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002213 const char * const sc_args[] = { "-e", };
2214 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2215 const char * const majpf_args[] = { "-e", "major-faults" };
2216 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2217 const char * const minpf_args[] = { "-e", "minor-faults" };
2218 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2219
David Ahern9aca7f12013-12-04 19:41:39 -07002220 /* +1 is for the event string below */
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002221 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2222 majpf_args_nr + minpf_args_nr + argc;
David Ahern5e2485b2013-09-28 13:13:01 -06002223 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2224
2225 if (rec_argv == NULL)
2226 return -ENOMEM;
2227
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002228 j = 0;
David Ahern5e2485b2013-09-28 13:13:01 -06002229 for (i = 0; i < ARRAY_SIZE(record_args); i++)
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002230 rec_argv[j++] = record_args[i];
2231
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002232 if (trace->trace_syscalls) {
2233 for (i = 0; i < sc_args_nr; i++)
2234 rec_argv[j++] = sc_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002235
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002236 /* event string may be different for older kernels - e.g., RHEL6 */
2237 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2238 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2239 else if (is_valid_tracepoint("syscalls:sys_enter"))
2240 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2241 else {
2242 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
Martin Kepplingerc896f852017-09-13 21:14:19 +02002243 free(rec_argv);
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002244 return -1;
2245 }
David Ahern9aca7f12013-12-04 19:41:39 -07002246 }
David Ahern9aca7f12013-12-04 19:41:39 -07002247
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002248 if (trace->trace_pgfaults & TRACE_PFMAJ)
2249 for (i = 0; i < majpf_args_nr; i++)
2250 rec_argv[j++] = majpf_args[i];
David Ahern5e2485b2013-09-28 13:13:01 -06002251
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002252 if (trace->trace_pgfaults & TRACE_PFMIN)
2253 for (i = 0; i < minpf_args_nr; i++)
2254 rec_argv[j++] = minpf_args[i];
2255
2256 for (i = 0; i < (unsigned int)argc; i++)
2257 rec_argv[j++] = argv[i];
2258
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03002259 return cmd_record(j, rec_argv);
David Ahern5e2485b2013-09-28 13:13:01 -06002260}
2261
David Ahernbf2575c2013-10-08 21:26:53 -06002262static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2263
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002264static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002265{
Arnaldo Carvalho de Meloef503832013-11-07 16:41:19 -03002266 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
Jiri Olsa8dd2a132015-09-07 10:38:06 +02002267
2268 if (IS_ERR(evsel))
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002269 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002270
2271 if (perf_evsel__field(evsel, "pathname") == NULL) {
2272 perf_evsel__delete(evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002273 return false;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002274 }
2275
Arnaldo Carvalho de Melo744a9712013-11-06 10:17:38 -03002276 evsel->handler = trace__vfs_getname;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002277 perf_evlist__add(evlist, evsel);
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002278 return true;
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002279}
2280
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002281static struct perf_evsel *perf_evsel__new_pgfault(u64 config)
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002282{
2283 struct perf_evsel *evsel;
2284 struct perf_event_attr attr = {
2285 .type = PERF_TYPE_SOFTWARE,
2286 .mmap_data = 1,
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002287 };
2288
2289 attr.config = config;
Arnaldo Carvalho de Melo05247982014-07-23 18:15:09 -03002290 attr.sample_period = 1;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002291
2292 event_attr_init(&attr);
2293
2294 evsel = perf_evsel__new(&attr);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002295 if (evsel)
2296 evsel->handler = trace__pgfault;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002297
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002298 return evsel;
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002299}
2300
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002301static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2302{
2303 const u32 type = event->header.type;
2304 struct perf_evsel *evsel;
2305
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002306 if (type != PERF_RECORD_SAMPLE) {
2307 trace__process_event(trace, trace->host, event, sample);
2308 return;
2309 }
2310
2311 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2312 if (evsel == NULL) {
2313 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2314 return;
2315 }
2316
Arnaldo Carvalho de Meloe6001982016-03-31 15:16:28 -03002317 trace__set_base_time(trace, evsel, sample);
2318
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002319 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2320 sample->raw_data == NULL) {
2321 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2322 perf_evsel__name(evsel), sample->tid,
2323 sample->cpu, sample->raw_size);
2324 } else {
2325 tracepoint_handler handler = evsel->handler;
2326 handler(trace, evsel, event, sample);
2327 }
2328}
2329
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002330static int trace__add_syscall_newtp(struct trace *trace)
2331{
2332 int ret = -1;
2333 struct perf_evlist *evlist = trace->evlist;
2334 struct perf_evsel *sys_enter, *sys_exit;
2335
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002336 sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002337 if (sys_enter == NULL)
2338 goto out;
2339
2340 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2341 goto out_delete_sys_enter;
2342
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002343 sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit);
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002344 if (sys_exit == NULL)
2345 goto out_delete_sys_enter;
2346
2347 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2348 goto out_delete_sys_exit;
2349
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002350 perf_evsel__config_callchain(sys_enter, &trace->opts, &callchain_param);
2351 perf_evsel__config_callchain(sys_exit, &trace->opts, &callchain_param);
2352
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002353 perf_evlist__add(evlist, sys_enter);
2354 perf_evlist__add(evlist, sys_exit);
2355
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03002356 if (callchain_param.enabled && !trace->kernel_syscallchains) {
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03002357 /*
2358 * We're interested only in the user space callchain
2359 * leading to the syscall, allow overriding that for
2360 * debugging reasons using --kernel_syscall_callchains
2361 */
2362 sys_exit->attr.exclude_callchain_kernel = 1;
2363 }
2364
Arnaldo Carvalho de Melo8b3ce752015-07-02 18:28:11 -03002365 trace->syscalls.events.sys_enter = sys_enter;
2366 trace->syscalls.events.sys_exit = sys_exit;
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002367
2368 ret = 0;
2369out:
2370 return ret;
2371
2372out_delete_sys_exit:
2373 perf_evsel__delete_priv(sys_exit);
2374out_delete_sys_enter:
2375 perf_evsel__delete_priv(sys_enter);
2376 goto out;
2377}
2378
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002379static int trace__set_ev_qualifier_filter(struct trace *trace)
2380{
2381 int err = -1;
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002382 struct perf_evsel *sys_exit;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002383 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2384 trace->ev_qualifier_ids.nr,
2385 trace->ev_qualifier_ids.entries);
2386
2387 if (filter == NULL)
2388 goto out_enomem;
2389
Mathieu Poirier3541c032016-09-16 08:44:04 -06002390 if (!perf_evsel__append_tp_filter(trace->syscalls.events.sys_enter,
2391 filter)) {
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002392 sys_exit = trace->syscalls.events.sys_exit;
Mathieu Poirier3541c032016-09-16 08:44:04 -06002393 err = perf_evsel__append_tp_filter(sys_exit, filter);
Mathieu Poirierb15d0a42016-09-16 08:44:03 -06002394 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002395
2396 free(filter);
2397out:
2398 return err;
2399out_enomem:
2400 errno = ENOMEM;
2401 goto out;
2402}
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002403
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002404static int trace__set_filter_loop_pids(struct trace *trace)
2405{
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002406 unsigned int nr = 1;
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002407 pid_t pids[32] = {
2408 getpid(),
2409 };
Arnaldo Carvalho de Melo082ab9a2017-07-20 11:32:05 -03002410 struct thread *thread = machine__find_thread(trace->host, pids[0], pids[0]);
2411
2412 while (thread && nr < ARRAY_SIZE(pids)) {
2413 struct thread *parent = machine__find_thread(trace->host, thread->ppid, thread->ppid);
2414
2415 if (parent == NULL)
2416 break;
2417
2418 if (!strcmp(thread__comm_str(parent), "sshd")) {
2419 pids[nr++] = parent->tid;
2420 break;
2421 }
2422 thread = parent;
2423 }
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002424
2425 return perf_evlist__set_filter_pids(trace->evlist, nr, pids);
2426}
2427
Namhyung Kimf15eb532012-10-05 14:02:16 +09002428static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002429{
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002430 struct perf_evlist *evlist = trace->evlist;
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002431 struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002432 int err = -1, i;
2433 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002434 const bool forks = argc > 0;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002435 bool draining = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002436
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002437 trace->live = true;
2438
Arnaldo Carvalho de Meloc27366f2015-07-02 18:24:51 -03002439 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002440 goto out_error_raw_syscalls;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002441
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002442 if (trace->trace_syscalls)
Arnaldo Carvalho de Melo08c98772015-08-04 17:01:04 -03002443 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002444
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002445 if ((trace->trace_pgfaults & TRACE_PFMAJ)) {
2446 pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ);
2447 if (pgfault_maj == NULL)
2448 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002449 perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002450 perf_evlist__add(evlist, pgfault_maj);
Arnaldo Carvalho de Meloe2726d92015-01-22 10:34:22 -03002451 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002452
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002453 if ((trace->trace_pgfaults & TRACE_PFMIN)) {
2454 pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN);
2455 if (pgfault_min == NULL)
2456 goto out_error_mem;
Arnaldo Carvalho de Melo08e26392018-01-12 13:29:05 -03002457 perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melo0ae537c2016-04-19 16:00:01 -03002458 perf_evlist__add(evlist, pgfault_min);
2459 }
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002460
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002461 if (trace->sched &&
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002462 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2463 trace__sched_stat_runtime))
2464 goto out_error_sched_stat_runtime;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002465
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002466 /*
2467 * If a global cgroup was set, apply it to all the events without an
2468 * explicit cgroup. I.e.:
2469 *
2470 * trace -G A -e sched:*switch
2471 *
2472 * Will set all raw_syscalls:sys_{enter,exit}, pgfault, vfs_getname, etc
2473 * _and_ sched:sched_switch to the 'A' cgroup, while:
2474 *
2475 * trace -e sched:*switch -G A
2476 *
2477 * will only set the sched:sched_switch event to the 'A' cgroup, all the
2478 * other events (raw_syscalls:sys_{enter,exit}, etc are left "without"
2479 * a cgroup (on the root cgroup, sys wide, etc).
2480 *
2481 * Multiple cgroups:
2482 *
2483 * trace -G A -e sched:*switch -G B
2484 *
2485 * the syscall ones go to the 'A' cgroup, the sched:sched_switch goes
2486 * to the 'B' cgroup.
2487 *
2488 * evlist__set_default_cgroup() grabs a reference of the passed cgroup
2489 * only for the evsels still without a cgroup, i.e. evsel->cgroup == NULL.
2490 */
2491 if (trace->cgroup)
2492 evlist__set_default_cgroup(trace->evlist, trace->cgroup);
2493
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002494 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2495 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002496 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002497 goto out_delete_evlist;
2498 }
2499
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002500 err = trace__symbols_init(trace, evlist);
2501 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002502 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002503 goto out_delete_evlist;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03002504 }
2505
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03002506 perf_evlist__config(evlist, &trace->opts, &callchain_param);
Arnaldo Carvalho de Melofde54b72016-04-11 18:42:37 -03002507
Namhyung Kimf15eb532012-10-05 14:02:16 +09002508 signal(SIGCHLD, sig_handler);
2509 signal(SIGINT, sig_handler);
2510
2511 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09002512 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Arnaldo Carvalho de Melo735f7e02014-01-03 14:56:49 -03002513 argv, false, NULL);
Namhyung Kimf15eb532012-10-05 14:02:16 +09002514 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002515 fprintf(trace->output, "Couldn't run the workload!\n");
Arnaldo Carvalho de Melo03ad9742014-01-03 15:56:06 -03002516 goto out_delete_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002517 }
2518 }
2519
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002520 err = perf_evlist__open(evlist);
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002521 if (err < 0)
2522 goto out_error_open;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002523
Wang Nanba504232016-02-26 09:31:54 +00002524 err = bpf__apply_obj_config();
2525 if (err) {
2526 char errbuf[BUFSIZ];
2527
2528 bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
2529 pr_err("ERROR: Apply config to BPF failed: %s\n",
2530 errbuf);
2531 goto out_error_open;
2532 }
2533
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002534 /*
2535 * Better not use !target__has_task() here because we need to cover the
2536 * case where no threads were specified in the command line, but a
2537 * workload was, and in that case we will fill in the thread_map when
2538 * we fork the workload in perf_evlist__prepare_workload.
2539 */
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002540 if (trace->filter_pids.nr > 0)
2541 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
Jiri Olsae13798c2015-06-23 00:36:02 +02002542 else if (thread_map__pid(evlist->threads, 0) == -1)
Arnaldo Carvalho de Melodd1a5032017-07-20 11:17:51 -03002543 err = trace__set_filter_loop_pids(trace);
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002544
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002545 if (err < 0)
2546 goto out_error_mem;
2547
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002548 if (trace->ev_qualifier_ids.nr > 0) {
2549 err = trace__set_ev_qualifier_filter(trace);
2550 if (err < 0)
2551 goto out_errno;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002552
Arnaldo Carvalho de Melo2e5e5f82015-08-03 17:12:29 -03002553 pr_debug("event qualifier tracepoint filter: %s\n",
2554 trace->syscalls.events.sys_exit->filter);
2555 }
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002556
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002557 err = perf_evlist__apply_filters(evlist, &evsel);
2558 if (err < 0)
2559 goto out_error_apply_filters;
Arnaldo Carvalho de Melo241b0572015-02-21 10:15:21 -08002560
Wang Nanf74b9d3a2017-12-03 02:00:37 +00002561 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages);
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002562 if (err < 0)
2563 goto out_error_mmap;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002564
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002565 if (!target__none(&trace->opts.target) && !trace->opts.initial_delay)
Arnaldo Carvalho de Melocb24d012015-04-22 10:04:23 -03002566 perf_evlist__enable(evlist);
2567
Namhyung Kimf15eb532012-10-05 14:02:16 +09002568 if (forks)
2569 perf_evlist__start_workload(evlist);
2570
Alexis Berlemonte36b7822016-10-10 07:43:28 +02002571 if (trace->opts.initial_delay) {
2572 usleep(trace->opts.initial_delay * 1000);
2573 perf_evlist__enable(evlist);
2574 }
2575
Jiri Olsae13798c2015-06-23 00:36:02 +02002576 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
Arnaldo Carvalho de Melo42052be2015-02-13 12:32:45 -03002577 evlist->threads->nr > 1 ||
2578 perf_evlist__first(evlist)->attr.inherit;
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002579
2580 /*
2581 * Now that we already used evsel->attr to ask the kernel to setup the
2582 * events, lets reuse evsel->attr.sample_max_stack as the limit in
2583 * trace__resolve_callchain(), allowing per-event max-stack settings
2584 * to override an explicitely set --max-stack global setting.
2585 */
2586 evlist__for_each_entry(evlist, evsel) {
Arnaldo Carvalho de Melo27de9b22018-05-28 16:00:29 -03002587 if (evsel__has_callchain(evsel) &&
Arnaldo Carvalho de Melobd3dda92018-01-15 11:33:53 -03002588 evsel->attr.sample_max_stack == 0)
2589 evsel->attr.sample_max_stack = trace->max_stack;
2590 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002591again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002592 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002593
2594 for (i = 0; i < evlist->nr_mmaps; i++) {
2595 union perf_event *event;
Kan Liangd7f55c62018-03-01 18:08:59 -05002596 struct perf_mmap *md;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002597
Kan Liangd7f55c62018-03-01 18:08:59 -05002598 md = &evlist->mmap[i];
Kan Liangb9bae2c2018-03-06 10:36:07 -05002599 if (perf_mmap__read_init(md) < 0)
Kan Liangd7f55c62018-03-01 18:08:59 -05002600 continue;
2601
Kan Liang0019dc872018-03-06 10:36:06 -05002602 while ((event = perf_mmap__read_event(md)) != NULL) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002603 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002604
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002605 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002606
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002607 err = perf_evlist__parse_sample(evlist, event, &sample);
2608 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002609 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002610 goto next_event;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002611 }
2612
Arnaldo Carvalho de Meloddbb1b12015-02-21 12:10:29 -08002613 trace__handle_event(trace, event, &sample);
Zhouyi Zhou8e50d382013-10-24 15:43:33 +08002614next_event:
Kan Liangd6ace3d2018-03-06 10:36:05 -05002615 perf_mmap__consume(md);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03002616
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002617 if (interrupted)
2618 goto out_disable;
Arnaldo Carvalho de Melo02ac5422015-04-22 11:11:57 -03002619
2620 if (done && !draining) {
2621 perf_evlist__disable(evlist);
2622 draining = true;
2623 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002624 }
Kan Liangd7f55c62018-03-01 18:08:59 -05002625 perf_mmap__read_done(md);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002626 }
2627
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03002628 if (trace->nr_events == before) {
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002629 int timeout = done ? 100 : -1;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002630
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002631 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2632 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2633 draining = true;
2634
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002635 goto again;
Arnaldo Carvalho de Melo46fb3c22014-09-22 14:39:48 -03002636 }
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002637 } else {
2638 goto again;
Namhyung Kimf15eb532012-10-05 14:02:16 +09002639 }
2640
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002641out_disable:
Arnaldo Carvalho de Melof3b623b2015-03-02 22:21:35 -03002642 thread__zput(trace->current);
2643
Arnaldo Carvalho de Meloba209f82013-10-16 11:57:33 -03002644 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002645
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002646 if (!err) {
2647 if (trace->summary)
2648 trace__fprintf_thread_summary(trace, trace->output);
2649
2650 if (trace->show_tool_stats) {
2651 fprintf(trace->output, "Stats:\n "
2652 " vfs_getname : %" PRIu64 "\n"
2653 " proc_getname: %" PRIu64 "\n",
2654 trace->stats.vfs_getname,
2655 trace->stats.proc_getname);
2656 }
2657 }
David Ahernbf2575c2013-10-08 21:26:53 -06002658
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002659out_delete_evlist:
Andrei Vagin33974a42017-11-07 16:22:45 -08002660 trace__symbols__exit(trace);
2661
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002662 perf_evlist__delete(evlist);
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03002663 cgroup__put(trace->cgroup);
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03002664 trace->evlist = NULL;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03002665 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002666 return err;
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002667{
2668 char errbuf[BUFSIZ];
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002669
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002670out_error_sched_stat_runtime:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002671 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
Arnaldo Carvalho de Melo2cc990b2015-01-22 11:13:43 -03002672 goto out_error;
2673
Arnaldo Carvalho de Melo801c67b2015-01-22 10:52:55 -03002674out_error_raw_syscalls:
Jiri Olsa988bdb32015-09-02 09:56:35 +02002675 tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002676 goto out_error;
2677
Arnaldo Carvalho de Meloe09b18d2014-12-11 18:04:10 -03002678out_error_mmap:
2679 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2680 goto out_error;
2681
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002682out_error_open:
2683 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2684
2685out_error:
Arnaldo Carvalho de Melo6ef068c2013-10-17 12:07:58 -03002686 fprintf(trace->output, "%s\n", errbuf);
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05302687 goto out_delete_evlist;
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002688
2689out_error_apply_filters:
2690 fprintf(trace->output,
2691 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2692 evsel->filter, perf_evsel__name(evsel), errno,
Arnaldo Carvalho de Meloc8b5f2c2016-07-06 11:56:20 -03002693 str_error_r(errno, errbuf, sizeof(errbuf)));
Arnaldo Carvalho de Melo94ad89b2015-07-03 17:42:03 -03002694 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002695}
Arnaldo Carvalho de Melo5ed08da2015-01-22 11:08:04 -03002696out_error_mem:
2697 fprintf(trace->output, "Not enough memory to run!\n");
2698 goto out_delete_evlist;
Arnaldo Carvalho de Melo19867b62015-07-04 12:44:59 -03002699
2700out_errno:
2701 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2702 goto out_delete_evlist;
Arnaldo Carvalho de Meloa8f23d82013-10-17 17:38:29 -03002703}
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002704
David Ahern6810fc92013-08-28 22:29:52 -06002705static int trace__replay(struct trace *trace)
2706{
2707 const struct perf_evsel_str_handler handlers[] = {
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03002708 { "probe:vfs_getname", trace__vfs_getname, },
David Ahern6810fc92013-08-28 22:29:52 -06002709 };
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002710 struct perf_data data = {
Jiri Olsaeae8ad82017-01-23 22:25:41 +01002711 .file = {
2712 .path = input_name,
2713 },
2714 .mode = PERF_DATA_MODE_READ,
2715 .force = trace->force,
Jiri Olsaf5fc14122013-10-15 16:27:32 +02002716 };
David Ahern6810fc92013-08-28 22:29:52 -06002717 struct perf_session *session;
Namhyung Kim003824e2013-11-12 15:25:00 +09002718 struct perf_evsel *evsel;
David Ahern6810fc92013-08-28 22:29:52 -06002719 int err = -1;
2720
2721 trace->tool.sample = trace__process_sample;
2722 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06002723 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06002724 trace->tool.comm = perf_event__process_comm;
2725 trace->tool.exit = perf_event__process_exit;
2726 trace->tool.fork = perf_event__process_fork;
2727 trace->tool.attr = perf_event__process_attr;
Hari Bathinif3b36142017-03-08 02:11:43 +05302728 trace->tool.tracing_data = perf_event__process_tracing_data;
David Ahern6810fc92013-08-28 22:29:52 -06002729 trace->tool.build_id = perf_event__process_build_id;
Hari Bathinif3b36142017-03-08 02:11:43 +05302730 trace->tool.namespaces = perf_event__process_namespaces;
David Ahern6810fc92013-08-28 22:29:52 -06002731
Jiri Olsa0a8cb852014-07-06 14:18:21 +02002732 trace->tool.ordered_events = true;
David Ahern6810fc92013-08-28 22:29:52 -06002733 trace->tool.ordering_requires_timestamps = true;
2734
2735 /* add tid to output */
2736 trace->multiple_threads = true;
2737
Jiri Olsa8ceb41d2017-01-23 22:07:59 +01002738 session = perf_session__new(&data, false, &trace->tool);
David Ahern6810fc92013-08-28 22:29:52 -06002739 if (session == NULL)
Taeung Song52e028342014-09-24 10:33:37 +09002740 return -1;
David Ahern6810fc92013-08-28 22:29:52 -06002741
David Ahernaa07df62016-11-25 09:29:52 -07002742 if (trace->opts.target.pid)
2743 symbol_conf.pid_list_str = strdup(trace->opts.target.pid);
2744
2745 if (trace->opts.target.tid)
2746 symbol_conf.tid_list_str = strdup(trace->opts.target.tid);
2747
Namhyung Kim0a7e6d12014-08-12 15:40:45 +09002748 if (symbol__init(&session->header.env) < 0)
Namhyung Kimcb2ffae2014-08-12 15:40:44 +09002749 goto out;
2750
David Ahern8fb598e2013-09-28 13:13:00 -06002751 trace->host = &session->machines.host;
2752
David Ahern6810fc92013-08-28 22:29:52 -06002753 err = perf_session__set_tracepoints_handlers(session, handlers);
2754 if (err)
2755 goto out;
2756
Namhyung Kim003824e2013-11-12 15:25:00 +09002757 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2758 "raw_syscalls:sys_enter");
David Ahern9aca7f12013-12-04 19:41:39 -07002759 /* older kernels have syscalls tp versus raw_syscalls */
2760 if (evsel == NULL)
2761 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2762 "syscalls:sys_enter");
David Ahern6810fc92013-08-28 22:29:52 -06002763
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002764 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002765 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002766 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002767 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2768 goto out;
2769 }
2770
2771 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2772 "raw_syscalls:sys_exit");
David Ahern9aca7f12013-12-04 19:41:39 -07002773 if (evsel == NULL)
2774 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2775 "syscalls:sys_exit");
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002776 if (evsel &&
Arnaldo Carvalho de Melo63f11c82018-08-02 14:27:09 -03002777 (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 ||
Stanislav Fomicheve281a962014-06-26 20:14:28 +04002778 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
Namhyung Kim003824e2013-11-12 15:25:00 +09002779 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
David Ahern6810fc92013-08-28 22:29:52 -06002780 goto out;
2781 }
2782
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03002783 evlist__for_each_entry(session->evlist, evsel) {
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04002784 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2785 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2786 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2787 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2788 evsel->handler = trace__pgfault;
2789 }
2790
David Ahern6810fc92013-08-28 22:29:52 -06002791 setup_pager();
2792
Arnaldo Carvalho de Melob7b61cb2015-03-03 11:58:45 -03002793 err = perf_session__process_events(session);
David Ahern6810fc92013-08-28 22:29:52 -06002794 if (err)
2795 pr_err("Failed to process events, error %d", err);
2796
David Ahernbf2575c2013-10-08 21:26:53 -06002797 else if (trace->summary)
2798 trace__fprintf_thread_summary(trace, trace->output);
2799
David Ahern6810fc92013-08-28 22:29:52 -06002800out:
2801 perf_session__delete(session);
2802
2803 return err;
2804}
2805
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002806static size_t trace__fprintf_threads_header(FILE *fp)
2807{
2808 size_t printed;
2809
Pekka Enberg99ff7152013-11-12 16:42:14 +02002810 printed = fprintf(fp, "\n Summary of events:\n\n");
David Ahernbf2575c2013-10-08 21:26:53 -06002811
2812 return printed;
2813}
2814
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002815DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs,
2816 struct stats *stats;
2817 double msecs;
2818 int syscall;
2819)
2820{
2821 struct int_node *source = rb_entry(nd, struct int_node, rb_node);
2822 struct stats *stats = source->priv;
2823
2824 entry->syscall = source->i;
2825 entry->stats = stats;
2826 entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0;
2827}
2828
David Ahernbf2575c2013-10-08 21:26:53 -06002829static size_t thread__dump_stats(struct thread_trace *ttrace,
2830 struct trace *trace, FILE *fp)
2831{
David Ahernbf2575c2013-10-08 21:26:53 -06002832 size_t printed = 0;
2833 struct syscall *sc;
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002834 struct rb_node *nd;
2835 DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002836
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002837 if (syscall_stats == NULL)
David Ahernbf2575c2013-10-08 21:26:53 -06002838 return 0;
2839
2840 printed += fprintf(fp, "\n");
2841
Milian Wolff834fd462015-08-06 11:24:29 +02002842 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2843 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2844 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
Pekka Enberg99ff7152013-11-12 16:42:14 +02002845
Arnaldo Carvalho de Melo98a91832016-06-23 11:34:10 -03002846 resort_rb__for_each_entry(nd, syscall_stats) {
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002847 struct stats *stats = syscall_stats_entry->stats;
David Ahernbf2575c2013-10-08 21:26:53 -06002848 if (stats) {
2849 double min = (double)(stats->min) / NSEC_PER_MSEC;
2850 double max = (double)(stats->max) / NSEC_PER_MSEC;
2851 double avg = avg_stats(stats);
2852 double pct;
2853 u64 n = (u64) stats->n;
2854
2855 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2856 avg /= NSEC_PER_MSEC;
2857
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002858 sc = &trace->syscalls.table[syscall_stats_entry->syscall];
Pekka Enberg99ff7152013-11-12 16:42:14 +02002859 printed += fprintf(fp, " %-15s", sc->name);
Milian Wolff834fd462015-08-06 11:24:29 +02002860 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002861 n, syscall_stats_entry->msecs, min, avg);
Pekka Enberg27a778b2013-11-13 14:21:48 +02002862 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
David Ahernbf2575c2013-10-08 21:26:53 -06002863 }
David Ahernbf2575c2013-10-08 21:26:53 -06002864 }
2865
Arnaldo Carvalho de Melob535d522016-05-04 16:06:26 -03002866 resort_rb__delete(syscall_stats);
David Ahernbf2575c2013-10-08 21:26:53 -06002867 printed += fprintf(fp, "\n\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002868
2869 return printed;
2870}
2871
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002872static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace)
David Ahern896cbb52013-09-28 13:12:59 -06002873{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002874 size_t printed = 0;
Namhyung Kim89dceb22014-10-06 09:46:03 +09002875 struct thread_trace *ttrace = thread__priv(thread);
David Ahern896cbb52013-09-28 13:12:59 -06002876 double ratio;
2877
2878 if (ttrace == NULL)
2879 return 0;
2880
2881 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2882
Pekka Enberg15e65c62013-11-14 18:43:30 +02002883 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
Pekka Enberg99ff7152013-11-12 16:42:14 +02002884 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
Pekka Enberg15e65c62013-11-14 18:43:30 +02002885 printed += fprintf(fp, "%.1f%%", ratio);
Stanislav Fomicheva2ea67d2014-07-08 22:05:16 +04002886 if (ttrace->pfmaj)
2887 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2888 if (ttrace->pfmin)
2889 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
Arnaldo Carvalho de Melo03548eb2016-05-05 15:46:50 -03002890 if (trace->sched)
2891 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
2892 else if (fputc('\n', fp) != EOF)
2893 ++printed;
2894
David Ahernbf2575c2013-10-08 21:26:53 -06002895 printed += thread__dump_stats(ttrace, trace, fp);
David Ahern896cbb52013-09-28 13:12:59 -06002896
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002897 return printed;
2898}
David Ahern896cbb52013-09-28 13:12:59 -06002899
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002900static unsigned long thread__nr_events(struct thread_trace *ttrace)
2901{
2902 return ttrace ? ttrace->nr_events : 0;
2903}
2904
2905DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)),
2906 struct thread *thread;
2907)
2908{
2909 entry->thread = rb_entry(nd, struct thread, rb_node);
David Ahern896cbb52013-09-28 13:12:59 -06002910}
2911
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002912static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2913{
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002914 size_t printed = trace__fprintf_threads_header(fp);
2915 struct rb_node *nd;
Kan Liang91e467b2017-09-10 19:23:14 -07002916 int i;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002917
Kan Liang91e467b2017-09-10 19:23:14 -07002918 for (i = 0; i < THREADS__TABLE_SIZE; i++) {
2919 DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host, i);
2920
2921 if (threads == NULL) {
2922 fprintf(fp, "%s", "Error sorting output by nr_events!\n");
2923 return 0;
2924 }
2925
2926 resort_rb__for_each_entry(nd, threads)
2927 printed += trace__fprintf_thread(fp, threads_entry->thread, trace);
2928
2929 resort_rb__delete(threads);
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002930 }
Arnaldo Carvalho de Melo96c14452016-05-04 12:47:16 -03002931 return printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002932}
2933
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03002934static int trace__set_duration(const struct option *opt, const char *str,
2935 int unset __maybe_unused)
2936{
2937 struct trace *trace = opt->value;
2938
2939 trace->duration_filter = atof(str);
2940 return 0;
2941}
2942
Arnaldo Carvalho de Melof078c382015-02-21 11:36:52 -08002943static int trace__set_filter_pids(const struct option *opt, const char *str,
2944 int unset __maybe_unused)
2945{
2946 int ret = -1;
2947 size_t i;
2948 struct trace *trace = opt->value;
2949 /*
2950 * FIXME: introduce a intarray class, plain parse csv and create a
2951 * { int nr, int entries[] } struct...
2952 */
2953 struct intlist *list = intlist__new(str);
2954
2955 if (list == NULL)
2956 return -1;
2957
2958 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2959 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2960
2961 if (trace->filter_pids.entries == NULL)
2962 goto out;
2963
2964 trace->filter_pids.entries[0] = getpid();
2965
2966 for (i = 1; i < trace->filter_pids.nr; ++i)
2967 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2968
2969 intlist__delete(list);
2970 ret = 0;
2971out:
2972 return ret;
2973}
2974
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002975static int trace__open_output(struct trace *trace, const char *filename)
2976{
2977 struct stat st;
2978
2979 if (!stat(filename, &st) && st.st_size) {
2980 char oldname[PATH_MAX];
2981
2982 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2983 unlink(oldname);
2984 rename(filename, oldname);
2985 }
2986
2987 trace->output = fopen(filename, "w");
2988
2989 return trace->output == NULL ? -errno : 0;
2990}
2991
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04002992static int parse_pagefaults(const struct option *opt, const char *str,
2993 int unset __maybe_unused)
2994{
2995 int *trace_pgfaults = opt->value;
2996
2997 if (strcmp(str, "all") == 0)
2998 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2999 else if (strcmp(str, "maj") == 0)
3000 *trace_pgfaults |= TRACE_PFMAJ;
3001 else if (strcmp(str, "min") == 0)
3002 *trace_pgfaults |= TRACE_PFMIN;
3003 else
3004 return -1;
3005
3006 return 0;
3007}
3008
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003009static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
3010{
3011 struct perf_evsel *evsel;
3012
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -03003013 evlist__for_each_entry(evlist, evsel)
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003014 evsel->handler = handler;
3015}
3016
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003017static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist)
3018{
3019 struct perf_evsel *evsel;
3020
3021 evlist__for_each_entry(evlist, evsel) {
3022 if (evsel->priv || !evsel->tp_format)
3023 continue;
3024
3025 if (strcmp(evsel->tp_format->system, "syscalls"))
3026 continue;
3027
3028 if (perf_evsel__init_syscall_tp(evsel))
3029 return -1;
3030
3031 if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) {
3032 struct syscall_tp *sc = evsel->priv;
3033
3034 if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)))
3035 return -1;
3036 } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) {
3037 struct syscall_tp *sc = evsel->priv;
3038
3039 if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap))
3040 return -1;
3041 }
3042 }
3043
3044 return 0;
3045}
3046
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003047/*
3048 * XXX: Hackish, just splitting the combined -e+--event (syscalls
3049 * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use
3050 * existing facilities unchanged (trace->ev_qualifier + parse_options()).
3051 *
3052 * It'd be better to introduce a parse_options() variant that would return a
3053 * list with the terms it didn't match to an event...
3054 */
3055static int trace__parse_events_option(const struct option *opt, const char *str,
3056 int unset __maybe_unused)
3057{
3058 struct trace *trace = (struct trace *)opt->value;
3059 const char *s = str;
3060 char *sep = NULL, *lists[2] = { NULL, NULL, };
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003061 int len = strlen(str) + 1, err = -1, list, idx;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003062 char *strace_groups_dir = system_path(STRACE_GROUPS_DIR);
3063 char group_name[PATH_MAX];
3064
3065 if (strace_groups_dir == NULL)
3066 return -1;
3067
3068 if (*s == '!') {
3069 ++s;
3070 trace->not_ev_qualifier = true;
3071 }
3072
3073 while (1) {
3074 if ((sep = strchr(s, ',')) != NULL)
3075 *sep = '\0';
3076
3077 list = 0;
Arnaldo Carvalho de Melo27702bc2017-08-31 11:50:04 -03003078 if (syscalltbl__id(trace->sctbl, s) >= 0 ||
3079 syscalltbl__strglobmatch_first(trace->sctbl, s, &idx) >= 0) {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003080 list = 1;
3081 } else {
3082 path__join(group_name, sizeof(group_name), strace_groups_dir, s);
3083 if (access(group_name, R_OK) == 0)
3084 list = 1;
3085 }
3086
3087 if (lists[list]) {
3088 sprintf(lists[list] + strlen(lists[list]), ",%s", s);
3089 } else {
3090 lists[list] = malloc(len);
3091 if (lists[list] == NULL)
3092 goto out;
3093 strcpy(lists[list], s);
3094 }
3095
3096 if (!sep)
3097 break;
3098
3099 *sep = ',';
3100 s = sep + 1;
3101 }
3102
3103 if (lists[1] != NULL) {
3104 struct strlist_config slist_config = {
3105 .dirname = strace_groups_dir,
3106 };
3107
3108 trace->ev_qualifier = strlist__new(lists[1], &slist_config);
3109 if (trace->ev_qualifier == NULL) {
3110 fputs("Not enough memory to parse event qualifier", trace->output);
3111 goto out;
3112 }
3113
3114 if (trace__validate_ev_qualifier(trace))
3115 goto out;
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003116 trace->trace_syscalls = true;
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003117 }
3118
3119 err = 0;
3120
3121 if (lists[0]) {
3122 struct option o = OPT_CALLBACK('e', "event", &trace->evlist, "event",
3123 "event selector. use 'perf list' to list available events",
3124 parse_events_option);
3125 err = parse_events_option(&o, lists[0], 0);
3126 }
3127out:
3128 if (sep)
3129 *sep = ',';
3130
3131 return err;
3132}
3133
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003134static int trace__parse_cgroups(const struct option *opt, const char *str, int unset)
3135{
3136 struct trace *trace = opt->value;
3137
3138 if (!list_empty(&trace->evlist->entries))
3139 return parse_cgroups(opt, str, unset);
3140
3141 trace->cgroup = evlist__findnew_cgroup(trace->evlist, str);
3142
3143 return 0;
3144}
3145
Arnaldo Carvalho de Melob0ad8ea2017-03-27 11:47:20 -03003146int cmd_trace(int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003147{
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003148 const char *trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09003149 "perf trace [<options>] [<command>]",
3150 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06003151 "perf trace record [<options>] [<command>]",
3152 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003153 NULL
3154 };
3155 struct trace trace = {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003156 .syscalls = {
3157 . max = -1,
3158 },
3159 .opts = {
3160 .target = {
3161 .uid = UINT_MAX,
3162 .uses_mmap = true,
3163 },
3164 .user_freq = UINT_MAX,
3165 .user_interval = ULLONG_MAX,
Arnaldo Carvalho de Melo509051e2014-01-14 17:52:14 -03003166 .no_buffering = true,
Arnaldo Carvalho de Melo38d54472014-12-12 17:28:32 -03003167 .mmap_pages = UINT_MAX,
Kan Liang9d9cad72015-06-17 09:51:11 -04003168 .proc_map_timeout = 500,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003169 },
Milian Wolff007d66a2015-08-05 16:52:23 -03003170 .output = stderr,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003171 .show_comm = true,
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003172 .trace_syscalls = false,
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003173 .kernel_syscallchains = false,
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003174 .max_stack = UINT_MAX,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003175 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003176 const char *output_name = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003177 const struct option trace_options[] = {
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003178 OPT_CALLBACK('e', "event", &trace, "event",
3179 "event/syscall selector. use 'perf list' to list available events",
3180 trace__parse_events_option),
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03003181 OPT_BOOLEAN(0, "comm", &trace.show_comm,
3182 "show the thread COMM next to its id"),
Arnaldo Carvalho de Meloc5227392013-09-27 18:06:19 -03003183 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
Arnaldo Carvalho de Melo017037f2017-01-09 17:26:26 -03003184 OPT_CALLBACK(0, "expr", &trace, "expr", "list of syscalls/events to trace",
3185 trace__parse_events_option),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003186 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06003187 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003188 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3189 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06003190 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003191 "trace events on existing thread id"),
Arnaldo Carvalho de Melofa0e4ff2015-04-23 11:59:20 -03003192 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3193 "pids to filter (by the kernel)", trace__set_filter_pids),
David Ahernac9be8e2013-08-20 11:15:45 -06003194 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003195 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06003196 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003197 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06003198 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003199 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02003200 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3201 "number of mmap data pages",
3202 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06003203 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003204 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03003205 OPT_CALLBACK(0, "duration", &trace, "float",
3206 "show only events with duration > N.M ms",
3207 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003208 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03003209 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06003210 OPT_BOOLEAN('T', "time", &trace.full_time,
3211 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo0a6545b2018-03-29 12:22:59 -03003212 OPT_BOOLEAN(0, "failure", &trace.failure_only,
3213 "Show only syscalls that failed"),
David Ahernfd2eaba2013-11-12 09:31:15 -07003214 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3215 "Show only syscall summary with statistics"),
3216 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3217 "Show all syscalls and summary with statistics"),
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003218 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3219 "Trace pagefaults", parse_pagefaults, "maj"),
Stanislav Fomicheve281a962014-06-26 20:14:28 +04003220 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
Yunlong Songe366a6d2015-04-02 21:47:18 +08003221 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
Milian Wolff566a0882016-04-08 13:34:15 +02003222 OPT_CALLBACK(0, "call-graph", &trace.opts,
3223 "record_mode[,record_size]", record_callchain_help,
3224 &record_parse_callchain_opt),
Arnaldo Carvalho de Melo44621812016-04-11 15:49:11 -03003225 OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains,
3226 "Show the kernel callchains on the syscall exit path"),
Arnaldo Carvalho de Melo5cf9c842016-04-15 11:10:31 -03003227 OPT_UINTEGER(0, "min-stack", &trace.min_stack,
3228 "Set the minimum stack depth when parsing the callchain, "
3229 "anything below the specified depth will be ignored."),
Arnaldo Carvalho de Meloc6d4a492016-04-14 18:29:08 -03003230 OPT_UINTEGER(0, "max-stack", &trace.max_stack,
3231 "Set the maximum stack depth when parsing the callchain, "
3232 "anything beyond the specified depth will be ignored. "
Arnaldo Carvalho de Melo4cb93442016-04-27 10:16:24 -03003233 "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)),
Arnaldo Carvalho de Melo591421e2018-01-22 11:38:54 -03003234 OPT_BOOLEAN(0, "print-sample", &trace.print_sample,
3235 "print the PERF_RECORD_SAMPLE PERF_SAMPLE_ info, for debugging"),
Kan Liang9d9cad72015-06-17 09:51:11 -04003236 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3237 "per thread proc mmap processing timeout in ms"),
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003238 OPT_CALLBACK('G', "cgroup", &trace, "name", "monitor event in cgroup name only",
3239 trace__parse_cgroups),
Alexis Berlemonte36b7822016-10-10 07:43:28 +02003240 OPT_UINTEGER('D', "delay", &trace.opts.initial_delay,
3241 "ms to wait before starting measurement after program "
3242 "start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003243 OPT_END()
3244 };
Arnaldo Carvalho de Meloccd62a82016-04-16 09:36:32 -03003245 bool __maybe_unused max_stack_user_set = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003246 bool mmap_pages_user_set = true;
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003247 struct perf_evsel *evsel;
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003248 const char * const trace_subcommands[] = { "record", NULL };
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003249 int err = -1;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003250 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003251
Arnaldo Carvalho de Melo4d08cb82015-02-24 15:35:55 -03003252 signal(SIGSEGV, sighandler_dump_stack);
3253 signal(SIGFPE, sighandler_dump_stack);
3254
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003255 trace.evlist = perf_evlist__new();
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003256 trace.sctbl = syscalltbl__new();
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003257
Arnaldo Carvalho de Melofd0db102016-04-04 13:32:20 -03003258 if (trace.evlist == NULL || trace.sctbl == NULL) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003259 pr_err("Not enough memory to run!\n");
He Kuangff8f6952015-05-11 12:28:36 +00003260 err = -ENOMEM;
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003261 goto out;
3262 }
3263
Yunlong Song6fdd9cb2015-03-18 21:35:57 +08003264 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3265 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
David Ahernfd2eaba2013-11-12 09:31:15 -07003266
Arnaldo Carvalho de Melo9ea42ba2018-03-06 16:30:51 -03003267 if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
3268 usage_with_options_msg(trace_usage, trace_options,
3269 "cgroup monitoring only available in system-wide mode");
3270 }
3271
Arnaldo Carvalho de Melo78e890e2018-08-07 16:19:05 -03003272 evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__");
3273 if (IS_ERR(evsel)) {
3274 bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf));
Arnaldo Carvalho de Meloe0b6d2e2018-08-07 15:40:13 -03003275 pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf);
3276 goto out;
3277 }
3278
Arnaldo Carvalho de Melod3d1c4bdf52018-08-07 16:21:44 -03003279 if (evsel) {
3280 if (perf_evsel__init_augmented_syscall_tp(evsel) ||
3281 perf_evsel__init_augmented_syscall_tp_args(evsel))
3282 goto out;
3283 trace.syscalls.events.augmented = evsel;
3284 }
3285
Wang Nand7888572016-04-08 15:07:24 +00003286 err = bpf__setup_stdout(trace.evlist);
3287 if (err) {
3288 bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf));
3289 pr_err("ERROR: Setup BPF stdout failed: %s\n", bf);
3290 goto out;
3291 }
3292
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003293 err = -1;
3294
Stanislav Fomichev598d02c2014-06-26 20:14:25 +04003295 if (trace.trace_pgfaults) {
3296 trace.opts.sample_address = true;
3297 trace.opts.sample_time = true;
3298 }
3299
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003300 if (trace.opts.mmap_pages == UINT_MAX)
3301 mmap_pages_user_set = false;
3302
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003303 if (trace.max_stack == UINT_MAX) {
Arnaldo Carvalho de Melo029c75e2018-05-17 16:31:32 -03003304 trace.max_stack = input_name ? PERF_MAX_STACK_DEPTH : sysctl__max_stack();
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003305 max_stack_user_set = false;
3306 }
3307
3308#ifdef HAVE_DWARF_UNWIND_SUPPORT
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003309 if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) {
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003310 record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false);
Arnaldo Carvalho de Melo75d50112018-01-15 10:39:55 -03003311 }
Arnaldo Carvalho de Melo05614992016-04-15 16:41:19 -03003312#endif
3313
Arnaldo Carvalho de Melo2ddd5c02016-04-18 12:09:08 -03003314 if (callchain_param.enabled) {
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003315 if (!mmap_pages_user_set && geteuid() == 0)
3316 trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4;
3317
Milian Wolff566a0882016-04-08 13:34:15 +02003318 symbol_conf.use_callchain = true;
Arnaldo Carvalho de Melof3e459d2016-04-15 17:52:34 -03003319 }
Milian Wolff566a0882016-04-08 13:34:15 +02003320
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003321 if (trace.evlist->nr_entries > 0) {
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003322 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
Arnaldo Carvalho de Melod32855f2018-08-02 15:09:24 -03003323 if (evlist__set_syscall_tp_fields(trace.evlist)) {
3324 perror("failed to set syscalls:* tracepoint fields");
3325 goto out;
3326 }
3327 }
Arnaldo Carvalho de Melo14a052d2015-02-03 12:58:57 -03003328
Stanislav Fomichev1e28fe02014-06-26 20:14:26 +04003329 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3330 return trace__record(&trace, argc-1, &argv[1]);
3331
3332 /* summary_only implies summary option, but don't overwrite summary if set */
3333 if (trace.summary_only)
3334 trace.summary = trace.summary_only;
3335
Arnaldo Carvalho de Melo726f3232015-02-06 10:16:45 +01003336 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3337 trace.evlist->nr_entries == 0 /* Was --events used? */) {
Arnaldo Carvalho de Melob9128852018-08-01 16:20:28 -03003338 trace.trace_syscalls = true;
Arnaldo Carvalho de Melo59247e32016-04-12 16:05:02 -03003339 }
3340
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003341 if (output_name != NULL) {
3342 err = trace__open_output(&trace, output_name);
3343 if (err < 0) {
3344 perror("failed to create output file");
3345 goto out;
3346 }
3347 }
3348
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003349 err = target__validate(&trace.opts.target);
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003350 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003351 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003352 fprintf(trace.output, "%s", bf);
3353 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09003354 }
3355
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003356 err = target__parse_uid(&trace.opts.target);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003357 if (err) {
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003358 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003359 fprintf(trace.output, "%s", bf);
3360 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003361 }
3362
Arnaldo Carvalho de Melo602ad872013-11-12 16:46:16 -03003363 if (!argc && target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09003364 trace.opts.target.system_wide = true;
3365
David Ahern6810fc92013-08-28 22:29:52 -06003366 if (input_name)
3367 err = trace__replay(&trace);
3368 else
3369 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003370
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03003371out_close:
3372 if (output_name != NULL)
3373 fclose(trace.output);
3374out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03003375 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03003376}