]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blame - tools/perf/builtin-trace.c
perf trace: Use a constant for the syscall formatting buffer
[mirror_ubuntu-focal-kernel.git] / tools / perf / builtin-trace.c
CommitLineData
4e319027 1#include <traceevent/event-parse.h>
514f1c67 2#include "builtin.h"
752fde44 3#include "util/color.h"
7c304ee0 4#include "util/debug.h"
514f1c67 5#include "util/evlist.h"
005438a8 6#include "util/exec_cmd.h"
752fde44 7#include "util/machine.h"
6810fc91 8#include "util/session.h"
752fde44 9#include "util/thread.h"
514f1c67 10#include "util/parse-options.h"
2ae3a312 11#include "util/strlist.h"
bdc89661 12#include "util/intlist.h"
514f1c67 13#include "util/thread_map.h"
bf2575c1 14#include "util/stat.h"
97978b3e 15#include "trace-event.h"
9aca7f17 16#include "util/parse-events.h"
514f1c67
ACM
17
18#include <libaudit.h>
19#include <stdlib.h>
ae685380 20#include <sys/mman.h>
f9da0b0c 21#include <linux/futex.h>
514f1c67 22
456857bd
IM
23/* For older distros: */
24#ifndef MAP_STACK
25# define MAP_STACK 0x20000
26#endif
27
28#ifndef MADV_HWPOISON
29# define MADV_HWPOISON 100
30#endif
31
32#ifndef MADV_MERGEABLE
33# define MADV_MERGEABLE 12
34#endif
35
36#ifndef MADV_UNMERGEABLE
37# define MADV_UNMERGEABLE 13
38#endif
39
79d26a6a
BH
40#ifndef EFD_SEMAPHORE
41# define EFD_SEMAPHORE 1
42#endif
43
c188e7ac
ACM
44#ifndef EFD_NONBLOCK
45# define EFD_NONBLOCK 00004000
46#endif
47
48#ifndef EFD_CLOEXEC
49# define EFD_CLOEXEC 02000000
50#endif
51
52#ifndef O_CLOEXEC
53# define O_CLOEXEC 02000000
54#endif
55
56#ifndef SOCK_DCCP
57# define SOCK_DCCP 6
58#endif
59
60#ifndef SOCK_CLOEXEC
61# define SOCK_CLOEXEC 02000000
62#endif
63
64#ifndef SOCK_NONBLOCK
65# define SOCK_NONBLOCK 00004000
66#endif
67
68#ifndef MSG_CMSG_CLOEXEC
69# define MSG_CMSG_CLOEXEC 0x40000000
70#endif
71
a1c2552d
ACM
72#ifndef PERF_FLAG_FD_NO_GROUP
73# define PERF_FLAG_FD_NO_GROUP (1UL << 0)
74#endif
75
76#ifndef PERF_FLAG_FD_OUTPUT
77# define PERF_FLAG_FD_OUTPUT (1UL << 1)
78#endif
79
80#ifndef PERF_FLAG_PID_CGROUP
81# define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */
82#endif
83
84#ifndef PERF_FLAG_FD_CLOEXEC
85# define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */
86#endif
87
88
77170988
ACM
89struct tp_field {
90 int offset;
91 union {
92 u64 (*integer)(struct tp_field *field, struct perf_sample *sample);
93 void *(*pointer)(struct tp_field *field, struct perf_sample *sample);
94 };
95};
96
97#define TP_UINT_FIELD(bits) \
98static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \
99{ \
55d43bca
DA
100 u##bits value; \
101 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
102 return value; \
77170988
ACM
103}
104
105TP_UINT_FIELD(8);
106TP_UINT_FIELD(16);
107TP_UINT_FIELD(32);
108TP_UINT_FIELD(64);
109
110#define TP_UINT_FIELD__SWAPPED(bits) \
111static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \
112{ \
55d43bca
DA
113 u##bits value; \
114 memcpy(&value, sample->raw_data + field->offset, sizeof(value)); \
77170988
ACM
115 return bswap_##bits(value);\
116}
117
118TP_UINT_FIELD__SWAPPED(16);
119TP_UINT_FIELD__SWAPPED(32);
120TP_UINT_FIELD__SWAPPED(64);
121
122static int tp_field__init_uint(struct tp_field *field,
123 struct format_field *format_field,
124 bool needs_swap)
125{
126 field->offset = format_field->offset;
127
128 switch (format_field->size) {
129 case 1:
130 field->integer = tp_field__u8;
131 break;
132 case 2:
133 field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16;
134 break;
135 case 4:
136 field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32;
137 break;
138 case 8:
139 field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64;
140 break;
141 default:
142 return -1;
143 }
144
145 return 0;
146}
147
148static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample)
149{
150 return sample->raw_data + field->offset;
151}
152
153static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field)
154{
155 field->offset = format_field->offset;
156 field->pointer = tp_field__ptr;
157 return 0;
158}
159
160struct syscall_tp {
161 struct tp_field id;
162 union {
163 struct tp_field args, ret;
164 };
165};
166
167static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel,
168 struct tp_field *field,
169 const char *name)
170{
171 struct format_field *format_field = perf_evsel__field(evsel, name);
172
173 if (format_field == NULL)
174 return -1;
175
176 return tp_field__init_uint(field, format_field, evsel->needs_swap);
177}
178
179#define perf_evsel__init_sc_tp_uint_field(evsel, name) \
180 ({ struct syscall_tp *sc = evsel->priv;\
181 perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); })
182
183static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel,
184 struct tp_field *field,
185 const char *name)
186{
187 struct format_field *format_field = perf_evsel__field(evsel, name);
188
189 if (format_field == NULL)
190 return -1;
191
192 return tp_field__init_ptr(field, format_field);
193}
194
195#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \
196 ({ struct syscall_tp *sc = evsel->priv;\
197 perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); })
198
199static void perf_evsel__delete_priv(struct perf_evsel *evsel)
200{
04662523 201 zfree(&evsel->priv);
77170988
ACM
202 perf_evsel__delete(evsel);
203}
204
96695d44
NK
205static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler)
206{
207 evsel->priv = malloc(sizeof(struct syscall_tp));
208 if (evsel->priv != NULL) {
209 if (perf_evsel__init_sc_tp_uint_field(evsel, id))
210 goto out_delete;
211
212 evsel->handler = handler;
213 return 0;
214 }
215
216 return -ENOMEM;
217
218out_delete:
04662523 219 zfree(&evsel->priv);
96695d44
NK
220 return -ENOENT;
221}
222
ef503831 223static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler)
77170988 224{
ef503831 225 struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction);
77170988 226
9aca7f17
DA
227 /* older kernel (e.g., RHEL6) use syscalls:{enter,exit} */
228 if (evsel == NULL)
229 evsel = perf_evsel__newtp("syscalls", direction);
230
77170988 231 if (evsel) {
96695d44 232 if (perf_evsel__init_syscall_tp(evsel, handler))
77170988 233 goto out_delete;
77170988
ACM
234 }
235
236 return evsel;
237
238out_delete:
239 perf_evsel__delete_priv(evsel);
240 return NULL;
241}
242
243#define perf_evsel__sc_tp_uint(evsel, name, sample) \
244 ({ struct syscall_tp *fields = evsel->priv; \
245 fields->name.integer(&fields->name, sample); })
246
247#define perf_evsel__sc_tp_ptr(evsel, name, sample) \
248 ({ struct syscall_tp *fields = evsel->priv; \
249 fields->name.pointer(&fields->name, sample); })
250
01533e97
ACM
251struct syscall_arg {
252 unsigned long val;
75b757ca
ACM
253 struct thread *thread;
254 struct trace *trace;
1f115cb7 255 void *parm;
01533e97
ACM
256 u8 idx;
257 u8 mask;
258};
259
1f115cb7 260struct strarray {
03e3adc9 261 int offset;
1f115cb7
ACM
262 int nr_entries;
263 const char **entries;
264};
265
266#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
267 .nr_entries = ARRAY_SIZE(array), \
268 .entries = array, \
269}
270
03e3adc9
ACM
271#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
272 .offset = off, \
273 .nr_entries = ARRAY_SIZE(array), \
274 .entries = array, \
275}
276
975b7c2f
ACM
277static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
278 const char *intfmt,
279 struct syscall_arg *arg)
1f115cb7 280{
1f115cb7 281 struct strarray *sa = arg->parm;
03e3adc9 282 int idx = arg->val - sa->offset;
1f115cb7
ACM
283
284 if (idx < 0 || idx >= sa->nr_entries)
975b7c2f 285 return scnprintf(bf, size, intfmt, arg->val);
1f115cb7
ACM
286
287 return scnprintf(bf, size, "%s", sa->entries[idx]);
288}
289
975b7c2f
ACM
290static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
291 struct syscall_arg *arg)
292{
293 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
294}
295
1f115cb7
ACM
296#define SCA_STRARRAY syscall_arg__scnprintf_strarray
297
844ae5b4
ACM
298#if defined(__i386__) || defined(__x86_64__)
299/*
300 * FIXME: Make this available to all arches as soon as the ioctl beautifier
301 * gets rewritten to support all arches.
302 */
78645cf3
ACM
303static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
304 struct syscall_arg *arg)
305{
306 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
307}
308
309#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
844ae5b4 310#endif /* defined(__i386__) || defined(__x86_64__) */
78645cf3 311
75b757ca
ACM
312static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
313 struct syscall_arg *arg);
314
315#define SCA_FD syscall_arg__scnprintf_fd
316
317static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
318 struct syscall_arg *arg)
319{
320 int fd = arg->val;
321
322 if (fd == AT_FDCWD)
323 return scnprintf(bf, size, "CWD");
324
325 return syscall_arg__scnprintf_fd(bf, size, arg);
326}
327
328#define SCA_FDAT syscall_arg__scnprintf_fd_at
329
330static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
331 struct syscall_arg *arg);
332
333#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
334
6e7eeb51 335static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
01533e97 336 struct syscall_arg *arg)
13d4ff3e 337{
01533e97 338 return scnprintf(bf, size, "%#lx", arg->val);
13d4ff3e
ACM
339}
340
beccb2b5
ACM
341#define SCA_HEX syscall_arg__scnprintf_hex
342
a1c2552d
ACM
343static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
344 struct syscall_arg *arg)
345{
346 return scnprintf(bf, size, "%d", arg->val);
347}
348
349#define SCA_INT syscall_arg__scnprintf_int
350
6e7eeb51 351static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
01533e97 352 struct syscall_arg *arg)
ae685380 353{
01533e97 354 int printed = 0, prot = arg->val;
ae685380
ACM
355
356 if (prot == PROT_NONE)
357 return scnprintf(bf, size, "NONE");
358#define P_MMAP_PROT(n) \
359 if (prot & PROT_##n) { \
360 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
361 prot &= ~PROT_##n; \
362 }
363
364 P_MMAP_PROT(EXEC);
365 P_MMAP_PROT(READ);
366 P_MMAP_PROT(WRITE);
367#ifdef PROT_SEM
368 P_MMAP_PROT(SEM);
369#endif
370 P_MMAP_PROT(GROWSDOWN);
371 P_MMAP_PROT(GROWSUP);
372#undef P_MMAP_PROT
373
374 if (prot)
375 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
376
377 return printed;
378}
379
380#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
381
6e7eeb51 382static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
01533e97 383 struct syscall_arg *arg)
941557e0 384{
01533e97 385 int printed = 0, flags = arg->val;
941557e0
ACM
386
387#define P_MMAP_FLAG(n) \
388 if (flags & MAP_##n) { \
389 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
390 flags &= ~MAP_##n; \
391 }
392
393 P_MMAP_FLAG(SHARED);
394 P_MMAP_FLAG(PRIVATE);
41817815 395#ifdef MAP_32BIT
941557e0 396 P_MMAP_FLAG(32BIT);
41817815 397#endif
941557e0
ACM
398 P_MMAP_FLAG(ANONYMOUS);
399 P_MMAP_FLAG(DENYWRITE);
400 P_MMAP_FLAG(EXECUTABLE);
401 P_MMAP_FLAG(FILE);
402 P_MMAP_FLAG(FIXED);
403 P_MMAP_FLAG(GROWSDOWN);
f2935f3e 404#ifdef MAP_HUGETLB
941557e0 405 P_MMAP_FLAG(HUGETLB);
f2935f3e 406#endif
941557e0
ACM
407 P_MMAP_FLAG(LOCKED);
408 P_MMAP_FLAG(NONBLOCK);
409 P_MMAP_FLAG(NORESERVE);
410 P_MMAP_FLAG(POPULATE);
411 P_MMAP_FLAG(STACK);
412#ifdef MAP_UNINITIALIZED
413 P_MMAP_FLAG(UNINITIALIZED);
414#endif
415#undef P_MMAP_FLAG
416
417 if (flags)
418 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
419
420 return printed;
421}
422
423#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
424
86998dda
AS
425static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
426 struct syscall_arg *arg)
427{
428 int printed = 0, flags = arg->val;
429
430#define P_MREMAP_FLAG(n) \
431 if (flags & MREMAP_##n) { \
432 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
433 flags &= ~MREMAP_##n; \
434 }
435
436 P_MREMAP_FLAG(MAYMOVE);
437#ifdef MREMAP_FIXED
438 P_MREMAP_FLAG(FIXED);
439#endif
440#undef P_MREMAP_FLAG
441
442 if (flags)
443 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
444
445 return printed;
446}
447
448#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
449
6e7eeb51 450static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
01533e97 451 struct syscall_arg *arg)
9e9716d1 452{
01533e97 453 int behavior = arg->val;
9e9716d1
ACM
454
455 switch (behavior) {
456#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
457 P_MADV_BHV(NORMAL);
458 P_MADV_BHV(RANDOM);
459 P_MADV_BHV(SEQUENTIAL);
460 P_MADV_BHV(WILLNEED);
461 P_MADV_BHV(DONTNEED);
462 P_MADV_BHV(REMOVE);
463 P_MADV_BHV(DONTFORK);
464 P_MADV_BHV(DOFORK);
465 P_MADV_BHV(HWPOISON);
466#ifdef MADV_SOFT_OFFLINE
467 P_MADV_BHV(SOFT_OFFLINE);
468#endif
469 P_MADV_BHV(MERGEABLE);
470 P_MADV_BHV(UNMERGEABLE);
f2935f3e 471#ifdef MADV_HUGEPAGE
9e9716d1 472 P_MADV_BHV(HUGEPAGE);
f2935f3e
DA
473#endif
474#ifdef MADV_NOHUGEPAGE
9e9716d1 475 P_MADV_BHV(NOHUGEPAGE);
f2935f3e 476#endif
9e9716d1
ACM
477#ifdef MADV_DONTDUMP
478 P_MADV_BHV(DONTDUMP);
479#endif
480#ifdef MADV_DODUMP
481 P_MADV_BHV(DODUMP);
482#endif
483#undef P_MADV_PHV
484 default: break;
485 }
486
487 return scnprintf(bf, size, "%#x", behavior);
488}
489
490#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
491
5cea6ff2
ACM
492static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
493 struct syscall_arg *arg)
494{
495 int printed = 0, op = arg->val;
496
497 if (op == 0)
498 return scnprintf(bf, size, "NONE");
499#define P_CMD(cmd) \
500 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
501 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
502 op &= ~LOCK_##cmd; \
503 }
504
505 P_CMD(SH);
506 P_CMD(EX);
507 P_CMD(NB);
508 P_CMD(UN);
509 P_CMD(MAND);
510 P_CMD(RW);
511 P_CMD(READ);
512 P_CMD(WRITE);
513#undef P_OP
514
515 if (op)
516 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
517
518 return printed;
519}
520
521#define SCA_FLOCK syscall_arg__scnprintf_flock
522
01533e97 523static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
f9da0b0c
ACM
524{
525 enum syscall_futex_args {
526 SCF_UADDR = (1 << 0),
527 SCF_OP = (1 << 1),
528 SCF_VAL = (1 << 2),
529 SCF_TIMEOUT = (1 << 3),
530 SCF_UADDR2 = (1 << 4),
531 SCF_VAL3 = (1 << 5),
532 };
01533e97 533 int op = arg->val;
f9da0b0c
ACM
534 int cmd = op & FUTEX_CMD_MASK;
535 size_t printed = 0;
536
537 switch (cmd) {
538#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
01533e97
ACM
539 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
540 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
541 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
542 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
543 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
544 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
f9da0b0c 545 P_FUTEX_OP(WAKE_OP); break;
01533e97
ACM
546 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
547 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
548 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
549 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
550 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
f9da0b0c
ACM
551 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
552 default: printed = scnprintf(bf, size, "%#x", cmd); break;
553 }
554
555 if (op & FUTEX_PRIVATE_FLAG)
556 printed += scnprintf(bf + printed, size - printed, "|PRIV");
557
558 if (op & FUTEX_CLOCK_REALTIME)
559 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
560
561 return printed;
562}
563
efe6b882
ACM
564#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
565
03e3adc9
ACM
566static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
567static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
eac032c5 568
1f115cb7
ACM
569static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
570static DEFINE_STRARRAY(itimers);
571
efe6b882
ACM
572static const char *whences[] = { "SET", "CUR", "END",
573#ifdef SEEK_DATA
574"DATA",
575#endif
576#ifdef SEEK_HOLE
577"HOLE",
578#endif
579};
580static DEFINE_STRARRAY(whences);
f9da0b0c 581
80f587d5
ACM
582static const char *fcntl_cmds[] = {
583 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
584 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
585 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
586 "F_GETOWNER_UIDS",
587};
588static DEFINE_STRARRAY(fcntl_cmds);
589
c045bf02
ACM
590static const char *rlimit_resources[] = {
591 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
592 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
593 "RTTIME",
594};
595static DEFINE_STRARRAY(rlimit_resources);
596
eb5b1b14
ACM
597static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
598static DEFINE_STRARRAY(sighow);
599
4f8c1b74
DA
600static const char *clockid[] = {
601 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
602 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
603};
604static DEFINE_STRARRAY(clockid);
605
e10bce81
ACM
606static const char *socket_families[] = {
607 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
608 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
609 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
610 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
611 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
612 "ALG", "NFC", "VSOCK",
613};
614static DEFINE_STRARRAY(socket_families);
615
a28b24b2
ACM
616#ifndef SOCK_TYPE_MASK
617#define SOCK_TYPE_MASK 0xf
618#endif
619
620static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
621 struct syscall_arg *arg)
622{
623 size_t printed;
624 int type = arg->val,
625 flags = type & ~SOCK_TYPE_MASK;
626
627 type &= SOCK_TYPE_MASK;
628 /*
629 * Can't use a strarray, MIPS may override for ABI reasons.
630 */
631 switch (type) {
632#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
633 P_SK_TYPE(STREAM);
634 P_SK_TYPE(DGRAM);
635 P_SK_TYPE(RAW);
636 P_SK_TYPE(RDM);
637 P_SK_TYPE(SEQPACKET);
638 P_SK_TYPE(DCCP);
639 P_SK_TYPE(PACKET);
640#undef P_SK_TYPE
641 default:
642 printed = scnprintf(bf, size, "%#x", type);
643 }
644
645#define P_SK_FLAG(n) \
646 if (flags & SOCK_##n) { \
647 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
648 flags &= ~SOCK_##n; \
649 }
650
651 P_SK_FLAG(CLOEXEC);
652 P_SK_FLAG(NONBLOCK);
653#undef P_SK_FLAG
654
655 if (flags)
656 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
657
658 return printed;
659}
660
661#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
662
b2cc99fd
ACM
663#ifndef MSG_PROBE
664#define MSG_PROBE 0x10
665#endif
b6e8f8f4
DA
666#ifndef MSG_WAITFORONE
667#define MSG_WAITFORONE 0x10000
668#endif
b2cc99fd
ACM
669#ifndef MSG_SENDPAGE_NOTLAST
670#define MSG_SENDPAGE_NOTLAST 0x20000
671#endif
672#ifndef MSG_FASTOPEN
673#define MSG_FASTOPEN 0x20000000
674#endif
675
676static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
677 struct syscall_arg *arg)
678{
679 int printed = 0, flags = arg->val;
680
681 if (flags == 0)
682 return scnprintf(bf, size, "NONE");
683#define P_MSG_FLAG(n) \
684 if (flags & MSG_##n) { \
685 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
686 flags &= ~MSG_##n; \
687 }
688
689 P_MSG_FLAG(OOB);
690 P_MSG_FLAG(PEEK);
691 P_MSG_FLAG(DONTROUTE);
692 P_MSG_FLAG(TRYHARD);
693 P_MSG_FLAG(CTRUNC);
694 P_MSG_FLAG(PROBE);
695 P_MSG_FLAG(TRUNC);
696 P_MSG_FLAG(DONTWAIT);
697 P_MSG_FLAG(EOR);
698 P_MSG_FLAG(WAITALL);
699 P_MSG_FLAG(FIN);
700 P_MSG_FLAG(SYN);
701 P_MSG_FLAG(CONFIRM);
702 P_MSG_FLAG(RST);
703 P_MSG_FLAG(ERRQUEUE);
704 P_MSG_FLAG(NOSIGNAL);
705 P_MSG_FLAG(MORE);
706 P_MSG_FLAG(WAITFORONE);
707 P_MSG_FLAG(SENDPAGE_NOTLAST);
708 P_MSG_FLAG(FASTOPEN);
709 P_MSG_FLAG(CMSG_CLOEXEC);
710#undef P_MSG_FLAG
711
712 if (flags)
713 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
714
715 return printed;
716}
717
718#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
719
51108999
ACM
720static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
721 struct syscall_arg *arg)
722{
723 size_t printed = 0;
724 int mode = arg->val;
725
726 if (mode == F_OK) /* 0 */
727 return scnprintf(bf, size, "F");
728#define P_MODE(n) \
729 if (mode & n##_OK) { \
730 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
731 mode &= ~n##_OK; \
732 }
733
734 P_MODE(R);
735 P_MODE(W);
736 P_MODE(X);
737#undef P_MODE
738
739 if (mode)
740 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
741
742 return printed;
743}
744
745#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
746
be65a89a 747static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
01533e97 748 struct syscall_arg *arg)
be65a89a 749{
01533e97 750 int printed = 0, flags = arg->val;
be65a89a
ACM
751
752 if (!(flags & O_CREAT))
01533e97 753 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
be65a89a
ACM
754
755 if (flags == 0)
756 return scnprintf(bf, size, "RDONLY");
757#define P_FLAG(n) \
758 if (flags & O_##n) { \
759 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
760 flags &= ~O_##n; \
761 }
762
763 P_FLAG(APPEND);
764 P_FLAG(ASYNC);
765 P_FLAG(CLOEXEC);
766 P_FLAG(CREAT);
767 P_FLAG(DIRECT);
768 P_FLAG(DIRECTORY);
769 P_FLAG(EXCL);
770 P_FLAG(LARGEFILE);
771 P_FLAG(NOATIME);
772 P_FLAG(NOCTTY);
773#ifdef O_NONBLOCK
774 P_FLAG(NONBLOCK);
775#elif O_NDELAY
776 P_FLAG(NDELAY);
777#endif
778#ifdef O_PATH
779 P_FLAG(PATH);
780#endif
781 P_FLAG(RDWR);
782#ifdef O_DSYNC
783 if ((flags & O_SYNC) == O_SYNC)
784 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
785 else {
786 P_FLAG(DSYNC);
787 }
788#else
789 P_FLAG(SYNC);
790#endif
791 P_FLAG(TRUNC);
792 P_FLAG(WRONLY);
793#undef P_FLAG
794
795 if (flags)
796 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
797
798 return printed;
799}
800
801#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
802
a1c2552d
ACM
803static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
804 struct syscall_arg *arg)
805{
806 int printed = 0, flags = arg->val;
807
808 if (flags == 0)
809 return 0;
810
811#define P_FLAG(n) \
812 if (flags & PERF_FLAG_##n) { \
813 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
814 flags &= ~PERF_FLAG_##n; \
815 }
816
817 P_FLAG(FD_NO_GROUP);
818 P_FLAG(FD_OUTPUT);
819 P_FLAG(PID_CGROUP);
820 P_FLAG(FD_CLOEXEC);
821#undef P_FLAG
822
823 if (flags)
824 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
825
826 return printed;
827}
828
829#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
830
49af9e93
ACM
831static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
832 struct syscall_arg *arg)
833{
834 int printed = 0, flags = arg->val;
835
836 if (flags == 0)
837 return scnprintf(bf, size, "NONE");
838#define P_FLAG(n) \
839 if (flags & EFD_##n) { \
840 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
841 flags &= ~EFD_##n; \
842 }
843
844 P_FLAG(SEMAPHORE);
845 P_FLAG(CLOEXEC);
846 P_FLAG(NONBLOCK);
847#undef P_FLAG
848
849 if (flags)
850 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
851
852 return printed;
853}
854
855#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
856
46cce19b
ACM
857static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
858 struct syscall_arg *arg)
859{
860 int printed = 0, flags = arg->val;
861
862#define P_FLAG(n) \
863 if (flags & O_##n) { \
864 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
865 flags &= ~O_##n; \
866 }
867
868 P_FLAG(CLOEXEC);
869 P_FLAG(NONBLOCK);
870#undef P_FLAG
871
872 if (flags)
873 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
874
875 return printed;
876}
877
878#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
879
8bad5b0a
ACM
880static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
881{
882 int sig = arg->val;
883
884 switch (sig) {
885#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
886 P_SIGNUM(HUP);
887 P_SIGNUM(INT);
888 P_SIGNUM(QUIT);
889 P_SIGNUM(ILL);
890 P_SIGNUM(TRAP);
891 P_SIGNUM(ABRT);
892 P_SIGNUM(BUS);
893 P_SIGNUM(FPE);
894 P_SIGNUM(KILL);
895 P_SIGNUM(USR1);
896 P_SIGNUM(SEGV);
897 P_SIGNUM(USR2);
898 P_SIGNUM(PIPE);
899 P_SIGNUM(ALRM);
900 P_SIGNUM(TERM);
8bad5b0a
ACM
901 P_SIGNUM(CHLD);
902 P_SIGNUM(CONT);
903 P_SIGNUM(STOP);
904 P_SIGNUM(TSTP);
905 P_SIGNUM(TTIN);
906 P_SIGNUM(TTOU);
907 P_SIGNUM(URG);
908 P_SIGNUM(XCPU);
909 P_SIGNUM(XFSZ);
910 P_SIGNUM(VTALRM);
911 P_SIGNUM(PROF);
912 P_SIGNUM(WINCH);
913 P_SIGNUM(IO);
914 P_SIGNUM(PWR);
915 P_SIGNUM(SYS);
02c5bb4a
BH
916#ifdef SIGEMT
917 P_SIGNUM(EMT);
918#endif
919#ifdef SIGSTKFLT
920 P_SIGNUM(STKFLT);
921#endif
922#ifdef SIGSWI
923 P_SIGNUM(SWI);
924#endif
8bad5b0a
ACM
925 default: break;
926 }
927
928 return scnprintf(bf, size, "%#x", sig);
929}
930
931#define SCA_SIGNUM syscall_arg__scnprintf_signum
932
844ae5b4
ACM
933#if defined(__i386__) || defined(__x86_64__)
934/*
935 * FIXME: Make this available to all arches.
936 */
78645cf3
ACM
937#define TCGETS 0x5401
938
939static const char *tioctls[] = {
940 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
941 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
942 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
943 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
944 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
945 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
946 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
947 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
948 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
949 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
950 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
951 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
952 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
953 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
954 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
955};
956
957static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
844ae5b4 958#endif /* defined(__i386__) || defined(__x86_64__) */
78645cf3 959
453350dd
ACM
960#define STRARRAY(arg, name, array) \
961 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
962 .arg_parm = { [arg] = &strarray__##array, }
963
514f1c67
ACM
964static struct syscall_fmt {
965 const char *name;
aec1930b 966 const char *alias;
01533e97 967 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 968 void *arg_parm[6];
514f1c67
ACM
969 bool errmsg;
970 bool timeout;
04b34729 971 bool hexret;
514f1c67 972} syscall_fmts[] = {
51108999
ACM
973 { .name = "access", .errmsg = true,
974 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
aec1930b 975 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
beccb2b5
ACM
976 { .name = "brk", .hexret = true,
977 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
4f8c1b74 978 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
75b757ca 979 { .name = "close", .errmsg = true,
48000a1a 980 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
a14bb860 981 { .name = "connect", .errmsg = true, },
75b757ca 982 { .name = "dup", .errmsg = true,
48000a1a 983 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 984 { .name = "dup2", .errmsg = true,
48000a1a 985 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 986 { .name = "dup3", .errmsg = true,
48000a1a 987 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 988 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
49af9e93
ACM
989 { .name = "eventfd2", .errmsg = true,
990 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
75b757ca
ACM
991 { .name = "faccessat", .errmsg = true,
992 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
993 { .name = "fadvise64", .errmsg = true,
48000a1a 994 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 995 { .name = "fallocate", .errmsg = true,
48000a1a 996 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 997 { .name = "fchdir", .errmsg = true,
48000a1a 998 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 999 { .name = "fchmod", .errmsg = true,
48000a1a 1000 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1001 { .name = "fchmodat", .errmsg = true,
48000a1a 1002 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
75b757ca 1003 { .name = "fchown", .errmsg = true,
48000a1a 1004 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1005 { .name = "fchownat", .errmsg = true,
48000a1a 1006 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
75b757ca
ACM
1007 { .name = "fcntl", .errmsg = true,
1008 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1009 [1] = SCA_STRARRAY, /* cmd */ },
1010 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1011 { .name = "fdatasync", .errmsg = true,
48000a1a 1012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
5cea6ff2 1013 { .name = "flock", .errmsg = true,
75b757ca
ACM
1014 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1015 [1] = SCA_FLOCK, /* cmd */ }, },
1016 { .name = "fsetxattr", .errmsg = true,
48000a1a 1017 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1018 { .name = "fstat", .errmsg = true, .alias = "newfstat",
48000a1a 1019 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1020 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
48000a1a 1021 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
75b757ca 1022 { .name = "fstatfs", .errmsg = true,
48000a1a 1023 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1024 { .name = "fsync", .errmsg = true,
48000a1a 1025 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1026 { .name = "ftruncate", .errmsg = true,
48000a1a 1027 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
f9da0b0c
ACM
1028 { .name = "futex", .errmsg = true,
1029 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
75b757ca 1030 { .name = "futimesat", .errmsg = true,
48000a1a 1031 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
75b757ca 1032 { .name = "getdents", .errmsg = true,
48000a1a 1033 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1034 { .name = "getdents64", .errmsg = true,
48000a1a 1035 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd
ACM
1036 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1037 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
beccb2b5 1038 { .name = "ioctl", .errmsg = true,
48000a1a 1039 .arg_scnprintf = { [0] = SCA_FD, /* fd */
844ae5b4
ACM
1040#if defined(__i386__) || defined(__x86_64__)
1041/*
1042 * FIXME: Make this available to all arches.
1043 */
78645cf3
ACM
1044 [1] = SCA_STRHEXARRAY, /* cmd */
1045 [2] = SCA_HEX, /* arg */ },
1046 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
844ae5b4
ACM
1047#else
1048 [2] = SCA_HEX, /* arg */ }, },
1049#endif
8bad5b0a
ACM
1050 { .name = "kill", .errmsg = true,
1051 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
75b757ca 1052 { .name = "linkat", .errmsg = true,
48000a1a 1053 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
75b757ca
ACM
1054 { .name = "lseek", .errmsg = true,
1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1056 [2] = SCA_STRARRAY, /* whence */ },
1057 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
e5959683 1058 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
9e9716d1
ACM
1059 { .name = "madvise", .errmsg = true,
1060 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1061 [2] = SCA_MADV_BHV, /* behavior */ }, },
75b757ca 1062 { .name = "mkdirat", .errmsg = true,
48000a1a 1063 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
75b757ca 1064 { .name = "mknodat", .errmsg = true,
48000a1a 1065 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
3d903aa7
ACM
1066 { .name = "mlock", .errmsg = true,
1067 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1068 { .name = "mlockall", .errmsg = true,
1069 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5 1070 { .name = "mmap", .hexret = true,
ae685380 1071 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
941557e0 1072 [2] = SCA_MMAP_PROT, /* prot */
73faab3a
NK
1073 [3] = SCA_MMAP_FLAGS, /* flags */
1074 [4] = SCA_FD, /* fd */ }, },
beccb2b5 1075 { .name = "mprotect", .errmsg = true,
ae685380
ACM
1076 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1077 [2] = SCA_MMAP_PROT, /* prot */ }, },
1078 { .name = "mremap", .hexret = true,
1079 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
86998dda 1080 [3] = SCA_MREMAP_FLAGS, /* flags */
ae685380 1081 [4] = SCA_HEX, /* new_addr */ }, },
3d903aa7
ACM
1082 { .name = "munlock", .errmsg = true,
1083 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5
ACM
1084 { .name = "munmap", .errmsg = true,
1085 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
75b757ca 1086 { .name = "name_to_handle_at", .errmsg = true,
48000a1a 1087 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
75b757ca 1088 { .name = "newfstatat", .errmsg = true,
48000a1a 1089 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
be65a89a
ACM
1090 { .name = "open", .errmsg = true,
1091 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1092 { .name = "open_by_handle_at", .errmsg = true,
75b757ca
ACM
1093 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1094 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1095 { .name = "openat", .errmsg = true,
75b757ca
ACM
1096 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1097 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
a1c2552d
ACM
1098 { .name = "perf_event_open", .errmsg = true,
1099 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1100 [2] = SCA_INT, /* cpu */
1101 [3] = SCA_FD, /* group_fd */
1102 [4] = SCA_PERF_FLAGS, /* flags */ }, },
46cce19b
ACM
1103 { .name = "pipe2", .errmsg = true,
1104 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
aec1930b
ACM
1105 { .name = "poll", .errmsg = true, .timeout = true, },
1106 { .name = "ppoll", .errmsg = true, .timeout = true, },
75b757ca 1107 { .name = "pread", .errmsg = true, .alias = "pread64",
48000a1a 1108 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1109 { .name = "preadv", .errmsg = true, .alias = "pread",
48000a1a 1110 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1111 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
75b757ca 1112 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
48000a1a 1113 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1114 { .name = "pwritev", .errmsg = true,
48000a1a 1115 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1116 { .name = "read", .errmsg = true,
48000a1a 1117 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1118 { .name = "readlinkat", .errmsg = true,
48000a1a 1119 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
75b757ca 1120 { .name = "readv", .errmsg = true,
48000a1a 1121 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
b2cc99fd
ACM
1122 { .name = "recvfrom", .errmsg = true,
1123 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1124 { .name = "recvmmsg", .errmsg = true,
1125 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1126 { .name = "recvmsg", .errmsg = true,
1127 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
75b757ca 1128 { .name = "renameat", .errmsg = true,
48000a1a 1129 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
1130 { .name = "rt_sigaction", .errmsg = true,
1131 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
453350dd 1132 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
8bad5b0a
ACM
1133 { .name = "rt_sigqueueinfo", .errmsg = true,
1134 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1135 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1136 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
aec1930b 1137 { .name = "select", .errmsg = true, .timeout = true, },
b2cc99fd
ACM
1138 { .name = "sendmmsg", .errmsg = true,
1139 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
1140 { .name = "sendmsg", .errmsg = true,
1141 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
1142 { .name = "sendto", .errmsg = true,
1143 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
453350dd
ACM
1144 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1145 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
75b757ca 1146 { .name = "shutdown", .errmsg = true,
48000a1a 1147 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
e10bce81 1148 { .name = "socket", .errmsg = true,
a28b24b2
ACM
1149 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1150 [1] = SCA_SK_TYPE, /* type */ },
07120aa5
ACM
1151 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1152 { .name = "socketpair", .errmsg = true,
1153 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1154 [1] = SCA_SK_TYPE, /* type */ },
e10bce81 1155 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
aec1930b 1156 { .name = "stat", .errmsg = true, .alias = "newstat", },
75b757ca 1157 { .name = "symlinkat", .errmsg = true,
48000a1a 1158 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
1159 { .name = "tgkill", .errmsg = true,
1160 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1161 { .name = "tkill", .errmsg = true,
1162 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
e5959683 1163 { .name = "uname", .errmsg = true, .alias = "newuname", },
75b757ca
ACM
1164 { .name = "unlinkat", .errmsg = true,
1165 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
1166 { .name = "utimensat", .errmsg = true,
1167 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
1168 { .name = "write", .errmsg = true,
48000a1a 1169 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1170 { .name = "writev", .errmsg = true,
48000a1a 1171 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
514f1c67
ACM
1172};
1173
1174static int syscall_fmt__cmp(const void *name, const void *fmtp)
1175{
1176 const struct syscall_fmt *fmt = fmtp;
1177 return strcmp(name, fmt->name);
1178}
1179
1180static struct syscall_fmt *syscall_fmt__find(const char *name)
1181{
1182 const int nmemb = ARRAY_SIZE(syscall_fmts);
1183 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1184}
1185
1186struct syscall {
1187 struct event_format *tp_format;
f208bd8d
ACM
1188 int nr_args;
1189 struct format_field *args;
514f1c67 1190 const char *name;
5089f20e 1191 bool is_exit;
514f1c67 1192 struct syscall_fmt *fmt;
01533e97 1193 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 1194 void **arg_parm;
514f1c67
ACM
1195};
1196
60c907ab
ACM
1197static size_t fprintf_duration(unsigned long t, FILE *fp)
1198{
1199 double duration = (double)t / NSEC_PER_MSEC;
1200 size_t printed = fprintf(fp, "(");
1201
1202 if (duration >= 1.0)
1203 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1204 else if (duration >= 0.01)
1205 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1206 else
1207 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
c24ff998 1208 return printed + fprintf(fp, "): ");
60c907ab
ACM
1209}
1210
752fde44
ACM
1211struct thread_trace {
1212 u64 entry_time;
1213 u64 exit_time;
1214 bool entry_pending;
efd5745e 1215 unsigned long nr_events;
a2ea67d7 1216 unsigned long pfmaj, pfmin;
752fde44 1217 char *entry_str;
1302d88e 1218 double runtime_ms;
75b757ca
ACM
1219 struct {
1220 int max;
1221 char **table;
1222 } paths;
bf2575c1
DA
1223
1224 struct intlist *syscall_stats;
752fde44
ACM
1225};
1226
1227static struct thread_trace *thread_trace__new(void)
1228{
75b757ca
ACM
1229 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1230
1231 if (ttrace)
1232 ttrace->paths.max = -1;
1233
bf2575c1
DA
1234 ttrace->syscall_stats = intlist__new(NULL);
1235
75b757ca 1236 return ttrace;
752fde44
ACM
1237}
1238
c24ff998 1239static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
752fde44 1240{
efd5745e
ACM
1241 struct thread_trace *ttrace;
1242
752fde44
ACM
1243 if (thread == NULL)
1244 goto fail;
1245
89dceb22
NK
1246 if (thread__priv(thread) == NULL)
1247 thread__set_priv(thread, thread_trace__new());
48000a1a 1248
89dceb22 1249 if (thread__priv(thread) == NULL)
752fde44
ACM
1250 goto fail;
1251
89dceb22 1252 ttrace = thread__priv(thread);
efd5745e
ACM
1253 ++ttrace->nr_events;
1254
1255 return ttrace;
752fde44 1256fail:
c24ff998 1257 color_fprintf(fp, PERF_COLOR_RED,
752fde44
ACM
1258 "WARNING: not enough memory, dropping samples!\n");
1259 return NULL;
1260}
1261
598d02c5
SF
1262#define TRACE_PFMAJ (1 << 0)
1263#define TRACE_PFMIN (1 << 1)
1264
e4d44e83
ACM
1265static const size_t trace__entry_str_size = 2048;
1266
514f1c67 1267struct trace {
c24ff998 1268 struct perf_tool tool;
c522739d
ACM
1269 struct {
1270 int machine;
1271 int open_id;
1272 } audit;
514f1c67
ACM
1273 struct {
1274 int max;
1275 struct syscall *table;
c27366f0 1276 struct {
8b3ce757
ACM
1277 struct perf_evsel *sys_enter,
1278 *sys_exit;
c27366f0 1279 } events;
514f1c67 1280 } syscalls;
b4006796 1281 struct record_opts opts;
14a052df 1282 struct perf_evlist *evlist;
8fb598e5 1283 struct machine *host;
e596663e 1284 struct thread *current;
752fde44 1285 u64 base_time;
c24ff998 1286 FILE *output;
efd5745e 1287 unsigned long nr_events;
b059efdf 1288 struct strlist *ev_qualifier;
8b3ce757
ACM
1289 struct {
1290 size_t nr;
1291 int *entries;
1292 } ev_qualifier_ids;
c522739d 1293 const char *last_vfs_getname;
bdc89661
DA
1294 struct intlist *tid_list;
1295 struct intlist *pid_list;
f078c385
ACM
1296 struct {
1297 size_t nr;
1298 pid_t *entries;
1299 } filter_pids;
98eafce6
ACM
1300 double duration_filter;
1301 double runtime_ms;
1302 struct {
1303 u64 vfs_getname,
1304 proc_getname;
1305 } stats;
1306 bool not_ev_qualifier;
1307 bool live;
1308 bool full_time;
1302d88e 1309 bool sched;
752fde44 1310 bool multiple_threads;
bf2575c1 1311 bool summary;
fd2eabaf 1312 bool summary_only;
50c95cbd 1313 bool show_comm;
c522739d 1314 bool show_tool_stats;
e281a960 1315 bool trace_syscalls;
e366a6d8 1316 bool force;
08c98776 1317 bool vfs_getname;
598d02c5 1318 int trace_pgfaults;
514f1c67
ACM
1319};
1320
97119f37 1321static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
75b757ca 1322{
89dceb22 1323 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1324
1325 if (fd > ttrace->paths.max) {
1326 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1327
1328 if (npath == NULL)
1329 return -1;
1330
1331 if (ttrace->paths.max != -1) {
1332 memset(npath + ttrace->paths.max + 1, 0,
1333 (fd - ttrace->paths.max) * sizeof(char *));
1334 } else {
1335 memset(npath, 0, (fd + 1) * sizeof(char *));
1336 }
1337
1338 ttrace->paths.table = npath;
1339 ttrace->paths.max = fd;
1340 }
1341
1342 ttrace->paths.table[fd] = strdup(pathname);
1343
1344 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1345}
1346
97119f37
ACM
1347static int thread__read_fd_path(struct thread *thread, int fd)
1348{
1349 char linkname[PATH_MAX], pathname[PATH_MAX];
1350 struct stat st;
1351 int ret;
1352
1353 if (thread->pid_ == thread->tid) {
1354 scnprintf(linkname, sizeof(linkname),
1355 "/proc/%d/fd/%d", thread->pid_, fd);
1356 } else {
1357 scnprintf(linkname, sizeof(linkname),
1358 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1359 }
1360
1361 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1362 return -1;
1363
1364 ret = readlink(linkname, pathname, sizeof(pathname));
1365
1366 if (ret < 0 || ret > st.st_size)
1367 return -1;
1368
1369 pathname[ret] = '\0';
1370 return trace__set_fd_pathname(thread, fd, pathname);
1371}
1372
c522739d
ACM
1373static const char *thread__fd_path(struct thread *thread, int fd,
1374 struct trace *trace)
75b757ca 1375{
89dceb22 1376 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1377
1378 if (ttrace == NULL)
1379 return NULL;
1380
1381 if (fd < 0)
1382 return NULL;
1383
cdcd1e6b 1384 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
c522739d
ACM
1385 if (!trace->live)
1386 return NULL;
1387 ++trace->stats.proc_getname;
cdcd1e6b 1388 if (thread__read_fd_path(thread, fd))
c522739d
ACM
1389 return NULL;
1390 }
75b757ca
ACM
1391
1392 return ttrace->paths.table[fd];
1393}
1394
1395static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1396 struct syscall_arg *arg)
1397{
1398 int fd = arg->val;
1399 size_t printed = scnprintf(bf, size, "%d", fd);
c522739d 1400 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
75b757ca
ACM
1401
1402 if (path)
1403 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1404
1405 return printed;
1406}
1407
1408static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1409 struct syscall_arg *arg)
1410{
1411 int fd = arg->val;
1412 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
89dceb22 1413 struct thread_trace *ttrace = thread__priv(arg->thread);
75b757ca 1414
04662523
ACM
1415 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1416 zfree(&ttrace->paths.table[fd]);
75b757ca
ACM
1417
1418 return printed;
1419}
1420
ae9ed035
ACM
1421static bool trace__filter_duration(struct trace *trace, double t)
1422{
1423 return t < (trace->duration_filter * NSEC_PER_MSEC);
1424}
1425
752fde44
ACM
1426static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1427{
1428 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1429
60c907ab 1430 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
1431}
1432
f15eb531 1433static bool done = false;
ba209f85 1434static bool interrupted = false;
f15eb531 1435
ba209f85 1436static void sig_handler(int sig)
f15eb531
NK
1437{
1438 done = true;
ba209f85 1439 interrupted = sig == SIGINT;
f15eb531
NK
1440}
1441
752fde44 1442static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 1443 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
1444{
1445 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 1446 printed += fprintf_duration(duration, fp);
752fde44 1447
50c95cbd
ACM
1448 if (trace->multiple_threads) {
1449 if (trace->show_comm)
1902efe7 1450 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
38051234 1451 printed += fprintf(fp, "%d ", thread->tid);
50c95cbd 1452 }
752fde44
ACM
1453
1454 return printed;
1455}
1456
c24ff998 1457static int trace__process_event(struct trace *trace, struct machine *machine,
162f0bef 1458 union perf_event *event, struct perf_sample *sample)
752fde44
ACM
1459{
1460 int ret = 0;
1461
1462 switch (event->header.type) {
1463 case PERF_RECORD_LOST:
c24ff998 1464 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44 1465 "LOST %" PRIu64 " events!\n", event->lost.lost);
162f0bef 1466 ret = machine__process_lost_event(machine, event, sample);
752fde44 1467 default:
162f0bef 1468 ret = machine__process_event(machine, event, sample);
752fde44
ACM
1469 break;
1470 }
1471
1472 return ret;
1473}
1474
c24ff998 1475static int trace__tool_process(struct perf_tool *tool,
752fde44 1476 union perf_event *event,
162f0bef 1477 struct perf_sample *sample,
752fde44
ACM
1478 struct machine *machine)
1479{
c24ff998 1480 struct trace *trace = container_of(tool, struct trace, tool);
162f0bef 1481 return trace__process_event(trace, machine, event, sample);
752fde44
ACM
1482}
1483
1484static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1485{
0a7e6d1b 1486 int err = symbol__init(NULL);
752fde44
ACM
1487
1488 if (err)
1489 return err;
1490
8fb598e5
DA
1491 trace->host = machine__new_host();
1492 if (trace->host == NULL)
1493 return -ENOMEM;
752fde44 1494
959c2199 1495 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
706c3da4
ACM
1496 return -errno;
1497
a33fbd56 1498 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
9d9cad76
KL
1499 evlist->threads, trace__tool_process, false,
1500 trace->opts.proc_map_timeout);
752fde44
ACM
1501 if (err)
1502 symbol__exit();
1503
1504 return err;
1505}
1506
13d4ff3e
ACM
1507static int syscall__set_arg_fmts(struct syscall *sc)
1508{
1509 struct format_field *field;
1510 int idx = 0;
1511
f208bd8d 1512 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
13d4ff3e
ACM
1513 if (sc->arg_scnprintf == NULL)
1514 return -1;
1515
1f115cb7
ACM
1516 if (sc->fmt)
1517 sc->arg_parm = sc->fmt->arg_parm;
1518
f208bd8d 1519 for (field = sc->args; field; field = field->next) {
beccb2b5
ACM
1520 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1521 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1522 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e
ACM
1523 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1524 ++idx;
1525 }
1526
1527 return 0;
1528}
1529
514f1c67
ACM
1530static int trace__read_syscall_info(struct trace *trace, int id)
1531{
1532 char tp_name[128];
1533 struct syscall *sc;
c522739d 1534 const char *name = audit_syscall_to_name(id, trace->audit.machine);
3a531260
ACM
1535
1536 if (name == NULL)
1537 return -1;
514f1c67
ACM
1538
1539 if (id > trace->syscalls.max) {
1540 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1541
1542 if (nsyscalls == NULL)
1543 return -1;
1544
1545 if (trace->syscalls.max != -1) {
1546 memset(nsyscalls + trace->syscalls.max + 1, 0,
1547 (id - trace->syscalls.max) * sizeof(*sc));
1548 } else {
1549 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1550 }
1551
1552 trace->syscalls.table = nsyscalls;
1553 trace->syscalls.max = id;
1554 }
1555
1556 sc = trace->syscalls.table + id;
3a531260 1557 sc->name = name;
2ae3a312 1558
3a531260 1559 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 1560
aec1930b 1561 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
97978b3e 1562 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b
ACM
1563
1564 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1565 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
97978b3e 1566 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1567 }
514f1c67 1568
13d4ff3e
ACM
1569 if (sc->tp_format == NULL)
1570 return -1;
1571
f208bd8d
ACM
1572 sc->args = sc->tp_format->format.fields;
1573 sc->nr_args = sc->tp_format->format.nr_fields;
1574 /* drop nr field - not relevant here; does not exist on older kernels */
1575 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1576 sc->args = sc->args->next;
1577 --sc->nr_args;
1578 }
1579
5089f20e
ACM
1580 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1581
13d4ff3e 1582 return syscall__set_arg_fmts(sc);
514f1c67
ACM
1583}
1584
d0cc439b
ACM
1585static int trace__validate_ev_qualifier(struct trace *trace)
1586{
8b3ce757 1587 int err = 0, i;
d0cc439b
ACM
1588 struct str_node *pos;
1589
8b3ce757
ACM
1590 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1591 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1592 sizeof(trace->ev_qualifier_ids.entries[0]));
1593
1594 if (trace->ev_qualifier_ids.entries == NULL) {
1595 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1596 trace->output);
1597 err = -EINVAL;
1598 goto out;
1599 }
1600
1601 i = 0;
1602
d0cc439b
ACM
1603 strlist__for_each(pos, trace->ev_qualifier) {
1604 const char *sc = pos->s;
8b3ce757 1605 int id = audit_name_to_syscall(sc, trace->audit.machine);
d0cc439b 1606
8b3ce757 1607 if (id < 0) {
d0cc439b
ACM
1608 if (err == 0) {
1609 fputs("Error:\tInvalid syscall ", trace->output);
1610 err = -EINVAL;
1611 } else {
1612 fputs(", ", trace->output);
1613 }
1614
1615 fputs(sc, trace->output);
1616 }
8b3ce757
ACM
1617
1618 trace->ev_qualifier_ids.entries[i++] = id;
d0cc439b
ACM
1619 }
1620
1621 if (err < 0) {
1622 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1623 "\nHint:\tand: 'man syscalls'\n", trace->output);
8b3ce757
ACM
1624 zfree(&trace->ev_qualifier_ids.entries);
1625 trace->ev_qualifier_ids.nr = 0;
d0cc439b 1626 }
8b3ce757 1627out:
d0cc439b
ACM
1628 return err;
1629}
1630
55d43bca
DA
1631/*
1632 * args is to be interpreted as a series of longs but we need to handle
1633 * 8-byte unaligned accesses. args points to raw_data within the event
1634 * and raw_data is guaranteed to be 8-byte unaligned because it is
1635 * preceded by raw_size which is a u32. So we need to copy args to a temp
1636 * variable to read it. Most notably this avoids extended load instructions
1637 * on unaligned addresses
1638 */
1639
752fde44 1640static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
55d43bca 1641 unsigned char *args, struct trace *trace,
75b757ca 1642 struct thread *thread)
514f1c67 1643{
514f1c67 1644 size_t printed = 0;
55d43bca
DA
1645 unsigned char *p;
1646 unsigned long val;
514f1c67 1647
f208bd8d 1648 if (sc->args != NULL) {
514f1c67 1649 struct format_field *field;
01533e97
ACM
1650 u8 bit = 1;
1651 struct syscall_arg arg = {
75b757ca
ACM
1652 .idx = 0,
1653 .mask = 0,
1654 .trace = trace,
1655 .thread = thread,
01533e97 1656 };
6e7eeb51 1657
f208bd8d 1658 for (field = sc->args; field;
01533e97
ACM
1659 field = field->next, ++arg.idx, bit <<= 1) {
1660 if (arg.mask & bit)
6e7eeb51 1661 continue;
55d43bca
DA
1662
1663 /* special care for unaligned accesses */
1664 p = args + sizeof(unsigned long) * arg.idx;
1665 memcpy(&val, p, sizeof(val));
1666
4aa58232
ACM
1667 /*
1668 * Suppress this argument if its value is zero and
1669 * and we don't have a string associated in an
1670 * strarray for it.
1671 */
55d43bca 1672 if (val == 0 &&
4aa58232
ACM
1673 !(sc->arg_scnprintf &&
1674 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1675 sc->arg_parm[arg.idx]))
22ae5cf1
ACM
1676 continue;
1677
752fde44 1678 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 1679 "%s%s: ", printed ? ", " : "", field->name);
01533e97 1680 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
55d43bca 1681 arg.val = val;
1f115cb7
ACM
1682 if (sc->arg_parm)
1683 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
1684 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1685 size - printed, &arg);
6e7eeb51 1686 } else {
13d4ff3e 1687 printed += scnprintf(bf + printed, size - printed,
55d43bca 1688 "%ld", val);
6e7eeb51 1689 }
514f1c67
ACM
1690 }
1691 } else {
01533e97
ACM
1692 int i = 0;
1693
514f1c67 1694 while (i < 6) {
55d43bca
DA
1695 /* special care for unaligned accesses */
1696 p = args + sizeof(unsigned long) * i;
1697 memcpy(&val, p, sizeof(val));
752fde44
ACM
1698 printed += scnprintf(bf + printed, size - printed,
1699 "%sarg%d: %ld",
55d43bca 1700 printed ? ", " : "", i, val);
514f1c67
ACM
1701 ++i;
1702 }
1703 }
1704
1705 return printed;
1706}
1707
ba3d7dee 1708typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1709 union perf_event *event,
ba3d7dee
ACM
1710 struct perf_sample *sample);
1711
1712static struct syscall *trace__syscall_info(struct trace *trace,
bf2575c1 1713 struct perf_evsel *evsel, int id)
ba3d7dee 1714{
ba3d7dee
ACM
1715
1716 if (id < 0) {
adaa18bf
ACM
1717
1718 /*
1719 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1720 * before that, leaving at a higher verbosity level till that is
1721 * explained. Reproduced with plain ftrace with:
1722 *
1723 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1724 * grep "NR -1 " /t/trace_pipe
1725 *
1726 * After generating some load on the machine.
1727 */
1728 if (verbose > 1) {
1729 static u64 n;
1730 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1731 id, perf_evsel__name(evsel), ++n);
1732 }
ba3d7dee
ACM
1733 return NULL;
1734 }
1735
1736 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1737 trace__read_syscall_info(trace, id))
1738 goto out_cant_read;
1739
1740 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1741 goto out_cant_read;
1742
1743 return &trace->syscalls.table[id];
1744
1745out_cant_read:
7c304ee0
ACM
1746 if (verbose) {
1747 fprintf(trace->output, "Problems reading syscall %d", id);
1748 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1749 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1750 fputs(" information\n", trace->output);
1751 }
ba3d7dee
ACM
1752 return NULL;
1753}
1754
bf2575c1
DA
1755static void thread__update_stats(struct thread_trace *ttrace,
1756 int id, struct perf_sample *sample)
1757{
1758 struct int_node *inode;
1759 struct stats *stats;
1760 u64 duration = 0;
1761
1762 inode = intlist__findnew(ttrace->syscall_stats, id);
1763 if (inode == NULL)
1764 return;
1765
1766 stats = inode->priv;
1767 if (stats == NULL) {
1768 stats = malloc(sizeof(struct stats));
1769 if (stats == NULL)
1770 return;
1771 init_stats(stats);
1772 inode->priv = stats;
1773 }
1774
1775 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1776 duration = sample->time - ttrace->entry_time;
1777
1778 update_stats(stats, duration);
1779}
1780
e596663e
ACM
1781static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1782{
1783 struct thread_trace *ttrace;
1784 u64 duration;
1785 size_t printed;
1786
1787 if (trace->current == NULL)
1788 return 0;
1789
1790 ttrace = thread__priv(trace->current);
1791
1792 if (!ttrace->entry_pending)
1793 return 0;
1794
1795 duration = sample->time - ttrace->entry_time;
1796
1797 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1798 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1799 ttrace->entry_pending = false;
1800
1801 return printed;
1802}
1803
ba3d7dee 1804static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1805 union perf_event *event __maybe_unused,
ba3d7dee
ACM
1806 struct perf_sample *sample)
1807{
752fde44 1808 char *msg;
ba3d7dee 1809 void *args;
752fde44 1810 size_t printed = 0;
2ae3a312 1811 struct thread *thread;
b91fc39f 1812 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 1813 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1814 struct thread_trace *ttrace;
1815
1816 if (sc == NULL)
1817 return -1;
ba3d7dee 1818
8fb598e5 1819 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1820 ttrace = thread__trace(thread, trace->output);
2ae3a312 1821 if (ttrace == NULL)
b91fc39f 1822 goto out_put;
ba3d7dee 1823
77170988 1824 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
752fde44
ACM
1825
1826 if (ttrace->entry_str == NULL) {
e4d44e83 1827 ttrace->entry_str = malloc(trace__entry_str_size);
752fde44 1828 if (!ttrace->entry_str)
b91fc39f 1829 goto out_put;
752fde44
ACM
1830 }
1831
13f22a2d 1832 if (!trace->summary_only)
6ebad5c1 1833 trace__printf_interrupted_entry(trace, sample);
e596663e 1834
752fde44
ACM
1835 ttrace->entry_time = sample->time;
1836 msg = ttrace->entry_str;
e4d44e83 1837 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
752fde44 1838
e4d44e83 1839 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
75b757ca 1840 args, trace, thread);
752fde44 1841
5089f20e 1842 if (sc->is_exit) {
fd2eabaf 1843 if (!trace->duration_filter && !trace->summary_only) {
c24ff998
ACM
1844 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1845 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 1846 }
752fde44
ACM
1847 } else
1848 ttrace->entry_pending = true;
ba3d7dee 1849
f3b623b8
ACM
1850 if (trace->current != thread) {
1851 thread__put(trace->current);
1852 trace->current = thread__get(thread);
1853 }
b91fc39f
ACM
1854 err = 0;
1855out_put:
1856 thread__put(thread);
1857 return err;
ba3d7dee
ACM
1858}
1859
1860static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1861 union perf_event *event __maybe_unused,
ba3d7dee
ACM
1862 struct perf_sample *sample)
1863{
2c82c3ad 1864 long ret;
60c907ab 1865 u64 duration = 0;
2ae3a312 1866 struct thread *thread;
b91fc39f 1867 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 1868 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1869 struct thread_trace *ttrace;
1870
1871 if (sc == NULL)
1872 return -1;
ba3d7dee 1873
8fb598e5 1874 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1875 ttrace = thread__trace(thread, trace->output);
2ae3a312 1876 if (ttrace == NULL)
b91fc39f 1877 goto out_put;
ba3d7dee 1878
bf2575c1
DA
1879 if (trace->summary)
1880 thread__update_stats(ttrace, id, sample);
1881
77170988 1882 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
ba3d7dee 1883
c522739d
ACM
1884 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1885 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1886 trace->last_vfs_getname = NULL;
1887 ++trace->stats.vfs_getname;
1888 }
1889
752fde44
ACM
1890 ttrace->exit_time = sample->time;
1891
ae9ed035 1892 if (ttrace->entry_time) {
60c907ab 1893 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
1894 if (trace__filter_duration(trace, duration))
1895 goto out;
1896 } else if (trace->duration_filter)
1897 goto out;
60c907ab 1898
fd2eabaf
DA
1899 if (trace->summary_only)
1900 goto out;
1901
c24ff998 1902 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
1903
1904 if (ttrace->entry_pending) {
c24ff998 1905 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 1906 } else {
c24ff998
ACM
1907 fprintf(trace->output, " ... [");
1908 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1909 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
1910 }
1911
da3c9a44
ACM
1912 if (sc->fmt == NULL) {
1913signed_print:
2c82c3ad 1914 fprintf(trace->output, ") = %ld", ret);
da3c9a44 1915 } else if (ret < 0 && sc->fmt->errmsg) {
942a91ed 1916 char bf[STRERR_BUFSIZE];
ba3d7dee
ACM
1917 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1918 *e = audit_errno_to_name(-ret);
1919
c24ff998 1920 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 1921 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 1922 fprintf(trace->output, ") = 0 Timeout");
04b34729 1923 else if (sc->fmt->hexret)
2c82c3ad 1924 fprintf(trace->output, ") = %#lx", ret);
ba3d7dee 1925 else
da3c9a44 1926 goto signed_print;
ba3d7dee 1927
c24ff998 1928 fputc('\n', trace->output);
ae9ed035 1929out:
752fde44 1930 ttrace->entry_pending = false;
b91fc39f
ACM
1931 err = 0;
1932out_put:
1933 thread__put(thread);
1934 return err;
ba3d7dee
ACM
1935}
1936
c522739d 1937static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1938 union perf_event *event __maybe_unused,
c522739d
ACM
1939 struct perf_sample *sample)
1940{
1941 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1942 return 0;
1943}
1944
1302d88e 1945static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1946 union perf_event *event __maybe_unused,
1302d88e
ACM
1947 struct perf_sample *sample)
1948{
1949 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1950 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
8fb598e5 1951 struct thread *thread = machine__findnew_thread(trace->host,
314add6b
AH
1952 sample->pid,
1953 sample->tid);
c24ff998 1954 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
1955
1956 if (ttrace == NULL)
1957 goto out_dump;
1958
1959 ttrace->runtime_ms += runtime_ms;
1960 trace->runtime_ms += runtime_ms;
b91fc39f 1961 thread__put(thread);
1302d88e
ACM
1962 return 0;
1963
1964out_dump:
c24ff998 1965 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
1966 evsel->name,
1967 perf_evsel__strval(evsel, sample, "comm"),
1968 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1969 runtime,
1970 perf_evsel__intval(evsel, sample, "vruntime"));
b91fc39f 1971 thread__put(thread);
1302d88e
ACM
1972 return 0;
1973}
1974
14a052df
ACM
1975static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
1976 union perf_event *event __maybe_unused,
1977 struct perf_sample *sample)
1978{
1979 trace__printf_interrupted_entry(trace, sample);
1980 trace__fprintf_tstamp(trace, sample->time, trace->output);
0808921a
ACM
1981
1982 if (trace->trace_syscalls)
1983 fprintf(trace->output, "( ): ");
1984
1985 fprintf(trace->output, "%s:", evsel->name);
14a052df
ACM
1986
1987 if (evsel->tp_format) {
1988 event_format__fprintf(evsel->tp_format, sample->cpu,
1989 sample->raw_data, sample->raw_size,
1990 trace->output);
1991 }
1992
1993 fprintf(trace->output, ")\n");
1994 return 0;
1995}
1996
598d02c5
SF
1997static void print_location(FILE *f, struct perf_sample *sample,
1998 struct addr_location *al,
1999 bool print_dso, bool print_sym)
2000{
2001
2002 if ((verbose || print_dso) && al->map)
2003 fprintf(f, "%s@", al->map->dso->long_name);
2004
2005 if ((verbose || print_sym) && al->sym)
4414a3c5 2006 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
598d02c5
SF
2007 al->addr - al->sym->start);
2008 else if (al->map)
4414a3c5 2009 fprintf(f, "0x%" PRIx64, al->addr);
598d02c5 2010 else
4414a3c5 2011 fprintf(f, "0x%" PRIx64, sample->addr);
598d02c5
SF
2012}
2013
2014static int trace__pgfault(struct trace *trace,
2015 struct perf_evsel *evsel,
2016 union perf_event *event,
2017 struct perf_sample *sample)
2018{
2019 struct thread *thread;
2020 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2021 struct addr_location al;
2022 char map_type = 'd';
a2ea67d7 2023 struct thread_trace *ttrace;
b91fc39f 2024 int err = -1;
598d02c5
SF
2025
2026 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
a2ea67d7
SF
2027 ttrace = thread__trace(thread, trace->output);
2028 if (ttrace == NULL)
b91fc39f 2029 goto out_put;
a2ea67d7
SF
2030
2031 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2032 ttrace->pfmaj++;
2033 else
2034 ttrace->pfmin++;
2035
2036 if (trace->summary_only)
b91fc39f 2037 goto out;
598d02c5 2038
bb871a9c 2039 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
598d02c5
SF
2040 sample->ip, &al);
2041
2042 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2043
2044 fprintf(trace->output, "%sfault [",
2045 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2046 "maj" : "min");
2047
2048 print_location(trace->output, sample, &al, false, true);
2049
2050 fprintf(trace->output, "] => ");
2051
bb871a9c 2052 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
598d02c5
SF
2053 sample->addr, &al);
2054
2055 if (!al.map) {
bb871a9c 2056 thread__find_addr_location(thread, cpumode,
598d02c5
SF
2057 MAP__FUNCTION, sample->addr, &al);
2058
2059 if (al.map)
2060 map_type = 'x';
2061 else
2062 map_type = '?';
2063 }
2064
2065 print_location(trace->output, sample, &al, true, false);
2066
2067 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
b91fc39f
ACM
2068out:
2069 err = 0;
2070out_put:
2071 thread__put(thread);
2072 return err;
598d02c5
SF
2073}
2074
bdc89661
DA
2075static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2076{
2077 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2078 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2079 return false;
2080
2081 if (trace->pid_list || trace->tid_list)
2082 return true;
2083
2084 return false;
2085}
2086
6810fc91 2087static int trace__process_sample(struct perf_tool *tool,
0c82adcf 2088 union perf_event *event,
6810fc91
DA
2089 struct perf_sample *sample,
2090 struct perf_evsel *evsel,
2091 struct machine *machine __maybe_unused)
2092{
2093 struct trace *trace = container_of(tool, struct trace, tool);
2094 int err = 0;
2095
744a9719 2096 tracepoint_handler handler = evsel->handler;
6810fc91 2097
bdc89661
DA
2098 if (skip_sample(trace, sample))
2099 return 0;
2100
4bb09192 2101 if (!trace->full_time && trace->base_time == 0)
6810fc91
DA
2102 trace->base_time = sample->time;
2103
3160565f
DA
2104 if (handler) {
2105 ++trace->nr_events;
0c82adcf 2106 handler(trace, evsel, event, sample);
3160565f 2107 }
6810fc91
DA
2108
2109 return err;
2110}
2111
bdc89661
DA
2112static int parse_target_str(struct trace *trace)
2113{
2114 if (trace->opts.target.pid) {
2115 trace->pid_list = intlist__new(trace->opts.target.pid);
2116 if (trace->pid_list == NULL) {
2117 pr_err("Error parsing process id string\n");
2118 return -EINVAL;
2119 }
2120 }
2121
2122 if (trace->opts.target.tid) {
2123 trace->tid_list = intlist__new(trace->opts.target.tid);
2124 if (trace->tid_list == NULL) {
2125 pr_err("Error parsing thread id string\n");
2126 return -EINVAL;
2127 }
2128 }
2129
2130 return 0;
2131}
2132
1e28fe0a 2133static int trace__record(struct trace *trace, int argc, const char **argv)
5e2485b1
DA
2134{
2135 unsigned int rec_argc, i, j;
2136 const char **rec_argv;
2137 const char * const record_args[] = {
2138 "record",
2139 "-R",
2140 "-m", "1024",
2141 "-c", "1",
5e2485b1
DA
2142 };
2143
1e28fe0a
SF
2144 const char * const sc_args[] = { "-e", };
2145 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2146 const char * const majpf_args[] = { "-e", "major-faults" };
2147 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2148 const char * const minpf_args[] = { "-e", "minor-faults" };
2149 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2150
9aca7f17 2151 /* +1 is for the event string below */
1e28fe0a
SF
2152 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2153 majpf_args_nr + minpf_args_nr + argc;
5e2485b1
DA
2154 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2155
2156 if (rec_argv == NULL)
2157 return -ENOMEM;
2158
1e28fe0a 2159 j = 0;
5e2485b1 2160 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1e28fe0a
SF
2161 rec_argv[j++] = record_args[i];
2162
e281a960
SF
2163 if (trace->trace_syscalls) {
2164 for (i = 0; i < sc_args_nr; i++)
2165 rec_argv[j++] = sc_args[i];
2166
2167 /* event string may be different for older kernels - e.g., RHEL6 */
2168 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2169 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2170 else if (is_valid_tracepoint("syscalls:sys_enter"))
2171 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2172 else {
2173 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2174 return -1;
2175 }
9aca7f17 2176 }
9aca7f17 2177
1e28fe0a
SF
2178 if (trace->trace_pgfaults & TRACE_PFMAJ)
2179 for (i = 0; i < majpf_args_nr; i++)
2180 rec_argv[j++] = majpf_args[i];
2181
2182 if (trace->trace_pgfaults & TRACE_PFMIN)
2183 for (i = 0; i < minpf_args_nr; i++)
2184 rec_argv[j++] = minpf_args[i];
2185
2186 for (i = 0; i < (unsigned int)argc; i++)
2187 rec_argv[j++] = argv[i];
5e2485b1 2188
1e28fe0a 2189 return cmd_record(j, rec_argv, NULL);
5e2485b1
DA
2190}
2191
bf2575c1
DA
2192static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2193
08c98776 2194static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
c522739d 2195{
ef503831 2196 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
c522739d 2197 if (evsel == NULL)
08c98776 2198 return false;
c522739d
ACM
2199
2200 if (perf_evsel__field(evsel, "pathname") == NULL) {
2201 perf_evsel__delete(evsel);
08c98776 2202 return false;
c522739d
ACM
2203 }
2204
744a9719 2205 evsel->handler = trace__vfs_getname;
c522739d 2206 perf_evlist__add(evlist, evsel);
08c98776 2207 return true;
c522739d
ACM
2208}
2209
598d02c5
SF
2210static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2211 u64 config)
2212{
2213 struct perf_evsel *evsel;
2214 struct perf_event_attr attr = {
2215 .type = PERF_TYPE_SOFTWARE,
2216 .mmap_data = 1,
598d02c5
SF
2217 };
2218
2219 attr.config = config;
0524798c 2220 attr.sample_period = 1;
598d02c5
SF
2221
2222 event_attr_init(&attr);
2223
2224 evsel = perf_evsel__new(&attr);
2225 if (!evsel)
2226 return -ENOMEM;
2227
2228 evsel->handler = trace__pgfault;
2229 perf_evlist__add(evlist, evsel);
2230
2231 return 0;
2232}
2233
ddbb1b13
ACM
2234static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2235{
2236 const u32 type = event->header.type;
2237 struct perf_evsel *evsel;
2238
2239 if (!trace->full_time && trace->base_time == 0)
2240 trace->base_time = sample->time;
2241
2242 if (type != PERF_RECORD_SAMPLE) {
2243 trace__process_event(trace, trace->host, event, sample);
2244 return;
2245 }
2246
2247 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2248 if (evsel == NULL) {
2249 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2250 return;
2251 }
2252
2253 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2254 sample->raw_data == NULL) {
2255 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2256 perf_evsel__name(evsel), sample->tid,
2257 sample->cpu, sample->raw_size);
2258 } else {
2259 tracepoint_handler handler = evsel->handler;
2260 handler(trace, evsel, event, sample);
2261 }
2262}
2263
c27366f0
ACM
2264static int trace__add_syscall_newtp(struct trace *trace)
2265{
2266 int ret = -1;
2267 struct perf_evlist *evlist = trace->evlist;
2268 struct perf_evsel *sys_enter, *sys_exit;
2269
2270 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2271 if (sys_enter == NULL)
2272 goto out;
2273
2274 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2275 goto out_delete_sys_enter;
2276
2277 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2278 if (sys_exit == NULL)
2279 goto out_delete_sys_enter;
2280
2281 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2282 goto out_delete_sys_exit;
2283
2284 perf_evlist__add(evlist, sys_enter);
2285 perf_evlist__add(evlist, sys_exit);
2286
8b3ce757
ACM
2287 trace->syscalls.events.sys_enter = sys_enter;
2288 trace->syscalls.events.sys_exit = sys_exit;
c27366f0
ACM
2289
2290 ret = 0;
2291out:
2292 return ret;
2293
2294out_delete_sys_exit:
2295 perf_evsel__delete_priv(sys_exit);
2296out_delete_sys_enter:
2297 perf_evsel__delete_priv(sys_enter);
2298 goto out;
2299}
2300
19867b61
ACM
2301static int trace__set_ev_qualifier_filter(struct trace *trace)
2302{
2303 int err = -1;
2304 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2305 trace->ev_qualifier_ids.nr,
2306 trace->ev_qualifier_ids.entries);
2307
2308 if (filter == NULL)
2309 goto out_enomem;
2310
2311 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2312 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2313
2314 free(filter);
2315out:
2316 return err;
2317out_enomem:
2318 errno = ENOMEM;
2319 goto out;
2320}
c27366f0 2321
f15eb531 2322static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 2323{
14a052df 2324 struct perf_evlist *evlist = trace->evlist;
94ad89bc 2325 struct perf_evsel *evsel;
efd5745e
ACM
2326 int err = -1, i;
2327 unsigned long before;
f15eb531 2328 const bool forks = argc > 0;
46fb3c21 2329 bool draining = false;
514f1c67 2330
75b757ca
ACM
2331 trace->live = true;
2332
c27366f0 2333 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
801c67b0 2334 goto out_error_raw_syscalls;
514f1c67 2335
e281a960 2336 if (trace->trace_syscalls)
08c98776 2337 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
c522739d 2338
598d02c5 2339 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
e2726d99 2340 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
5ed08dae 2341 goto out_error_mem;
e2726d99 2342 }
598d02c5
SF
2343
2344 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2345 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
5ed08dae 2346 goto out_error_mem;
598d02c5 2347
1302d88e 2348 if (trace->sched &&
2cc990ba
ACM
2349 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2350 trace__sched_stat_runtime))
2351 goto out_error_sched_stat_runtime;
1302d88e 2352
514f1c67
ACM
2353 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2354 if (err < 0) {
c24ff998 2355 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
2356 goto out_delete_evlist;
2357 }
2358
752fde44
ACM
2359 err = trace__symbols_init(trace, evlist);
2360 if (err < 0) {
c24ff998 2361 fprintf(trace->output, "Problems initializing symbol libraries!\n");
03ad9747 2362 goto out_delete_evlist;
752fde44
ACM
2363 }
2364
f77a9518 2365 perf_evlist__config(evlist, &trace->opts);
514f1c67 2366
f15eb531
NK
2367 signal(SIGCHLD, sig_handler);
2368 signal(SIGINT, sig_handler);
2369
2370 if (forks) {
6ef73ec4 2371 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
735f7e0b 2372 argv, false, NULL);
f15eb531 2373 if (err < 0) {
c24ff998 2374 fprintf(trace->output, "Couldn't run the workload!\n");
03ad9747 2375 goto out_delete_evlist;
f15eb531
NK
2376 }
2377 }
2378
514f1c67 2379 err = perf_evlist__open(evlist);
a8f23d8f
ACM
2380 if (err < 0)
2381 goto out_error_open;
514f1c67 2382
241b057c
ACM
2383 /*
2384 * Better not use !target__has_task() here because we need to cover the
2385 * case where no threads were specified in the command line, but a
2386 * workload was, and in that case we will fill in the thread_map when
2387 * we fork the workload in perf_evlist__prepare_workload.
2388 */
f078c385
ACM
2389 if (trace->filter_pids.nr > 0)
2390 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
e13798c7 2391 else if (thread_map__pid(evlist->threads, 0) == -1)
f078c385
ACM
2392 err = perf_evlist__set_filter_pid(evlist, getpid());
2393
94ad89bc
ACM
2394 if (err < 0)
2395 goto out_error_mem;
2396
19867b61
ACM
2397 if (trace->ev_qualifier_ids.nr > 0) {
2398 err = trace__set_ev_qualifier_filter(trace);
2399 if (err < 0)
2400 goto out_errno;
19867b61 2401
2e5e5f87
ACM
2402 pr_debug("event qualifier tracepoint filter: %s\n",
2403 trace->syscalls.events.sys_exit->filter);
2404 }
19867b61 2405
94ad89bc
ACM
2406 err = perf_evlist__apply_filters(evlist, &evsel);
2407 if (err < 0)
2408 goto out_error_apply_filters;
241b057c 2409
f885037e 2410 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
e09b18d4
ACM
2411 if (err < 0)
2412 goto out_error_mmap;
514f1c67 2413
cb24d01d
ACM
2414 if (!target__none(&trace->opts.target))
2415 perf_evlist__enable(evlist);
2416
f15eb531
NK
2417 if (forks)
2418 perf_evlist__start_workload(evlist);
2419
e13798c7 2420 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
42052bea
ACM
2421 evlist->threads->nr > 1 ||
2422 perf_evlist__first(evlist)->attr.inherit;
514f1c67 2423again:
efd5745e 2424 before = trace->nr_events;
514f1c67
ACM
2425
2426 for (i = 0; i < evlist->nr_mmaps; i++) {
2427 union perf_event *event;
2428
2429 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
514f1c67 2430 struct perf_sample sample;
514f1c67 2431
efd5745e 2432 ++trace->nr_events;
514f1c67 2433
514f1c67
ACM
2434 err = perf_evlist__parse_sample(evlist, event, &sample);
2435 if (err) {
c24ff998 2436 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
8e50d384 2437 goto next_event;
514f1c67
ACM
2438 }
2439
ddbb1b13 2440 trace__handle_event(trace, event, &sample);
8e50d384
ZZ
2441next_event:
2442 perf_evlist__mmap_consume(evlist, i);
20c5f10e 2443
ba209f85
ACM
2444 if (interrupted)
2445 goto out_disable;
02ac5421
ACM
2446
2447 if (done && !draining) {
2448 perf_evlist__disable(evlist);
2449 draining = true;
2450 }
514f1c67
ACM
2451 }
2452 }
2453
efd5745e 2454 if (trace->nr_events == before) {
ba209f85 2455 int timeout = done ? 100 : -1;
f15eb531 2456
46fb3c21
ACM
2457 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2458 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2459 draining = true;
2460
ba209f85 2461 goto again;
46fb3c21 2462 }
ba209f85
ACM
2463 } else {
2464 goto again;
f15eb531
NK
2465 }
2466
ba209f85 2467out_disable:
f3b623b8
ACM
2468 thread__zput(trace->current);
2469
ba209f85 2470 perf_evlist__disable(evlist);
514f1c67 2471
c522739d
ACM
2472 if (!err) {
2473 if (trace->summary)
2474 trace__fprintf_thread_summary(trace, trace->output);
2475
2476 if (trace->show_tool_stats) {
2477 fprintf(trace->output, "Stats:\n "
2478 " vfs_getname : %" PRIu64 "\n"
2479 " proc_getname: %" PRIu64 "\n",
2480 trace->stats.vfs_getname,
2481 trace->stats.proc_getname);
2482 }
2483 }
bf2575c1 2484
514f1c67
ACM
2485out_delete_evlist:
2486 perf_evlist__delete(evlist);
14a052df 2487 trace->evlist = NULL;
75b757ca 2488 trace->live = false;
514f1c67 2489 return err;
6ef068cb
ACM
2490{
2491 char errbuf[BUFSIZ];
a8f23d8f 2492
2cc990ba
ACM
2493out_error_sched_stat_runtime:
2494 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2495 goto out_error;
2496
801c67b0 2497out_error_raw_syscalls:
2cc990ba 2498 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
a8f23d8f
ACM
2499 goto out_error;
2500
e09b18d4
ACM
2501out_error_mmap:
2502 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2503 goto out_error;
2504
a8f23d8f
ACM
2505out_error_open:
2506 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2507
2508out_error:
6ef068cb 2509 fprintf(trace->output, "%s\n", errbuf);
87f91868 2510 goto out_delete_evlist;
94ad89bc
ACM
2511
2512out_error_apply_filters:
2513 fprintf(trace->output,
2514 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2515 evsel->filter, perf_evsel__name(evsel), errno,
2516 strerror_r(errno, errbuf, sizeof(errbuf)));
2517 goto out_delete_evlist;
514f1c67 2518}
5ed08dae
ACM
2519out_error_mem:
2520 fprintf(trace->output, "Not enough memory to run!\n");
2521 goto out_delete_evlist;
19867b61
ACM
2522
2523out_errno:
2524 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2525 goto out_delete_evlist;
a8f23d8f 2526}
514f1c67 2527
6810fc91
DA
2528static int trace__replay(struct trace *trace)
2529{
2530 const struct perf_evsel_str_handler handlers[] = {
c522739d 2531 { "probe:vfs_getname", trace__vfs_getname, },
6810fc91 2532 };
f5fc1412
JO
2533 struct perf_data_file file = {
2534 .path = input_name,
2535 .mode = PERF_DATA_MODE_READ,
e366a6d8 2536 .force = trace->force,
f5fc1412 2537 };
6810fc91 2538 struct perf_session *session;
003824e8 2539 struct perf_evsel *evsel;
6810fc91
DA
2540 int err = -1;
2541
2542 trace->tool.sample = trace__process_sample;
2543 trace->tool.mmap = perf_event__process_mmap;
384c671e 2544 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
2545 trace->tool.comm = perf_event__process_comm;
2546 trace->tool.exit = perf_event__process_exit;
2547 trace->tool.fork = perf_event__process_fork;
2548 trace->tool.attr = perf_event__process_attr;
2549 trace->tool.tracing_data = perf_event__process_tracing_data;
2550 trace->tool.build_id = perf_event__process_build_id;
2551
0a8cb85c 2552 trace->tool.ordered_events = true;
6810fc91
DA
2553 trace->tool.ordering_requires_timestamps = true;
2554
2555 /* add tid to output */
2556 trace->multiple_threads = true;
2557
f5fc1412 2558 session = perf_session__new(&file, false, &trace->tool);
6810fc91 2559 if (session == NULL)
52e02834 2560 return -1;
6810fc91 2561
0a7e6d1b 2562 if (symbol__init(&session->header.env) < 0)
cb2ffae2
NK
2563 goto out;
2564
8fb598e5
DA
2565 trace->host = &session->machines.host;
2566
6810fc91
DA
2567 err = perf_session__set_tracepoints_handlers(session, handlers);
2568 if (err)
2569 goto out;
2570
003824e8
NK
2571 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2572 "raw_syscalls:sys_enter");
9aca7f17
DA
2573 /* older kernels have syscalls tp versus raw_syscalls */
2574 if (evsel == NULL)
2575 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2576 "syscalls:sys_enter");
003824e8 2577
e281a960
SF
2578 if (evsel &&
2579 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2580 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
003824e8
NK
2581 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2582 goto out;
2583 }
2584
2585 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2586 "raw_syscalls:sys_exit");
9aca7f17
DA
2587 if (evsel == NULL)
2588 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2589 "syscalls:sys_exit");
e281a960
SF
2590 if (evsel &&
2591 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2592 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
003824e8 2593 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
6810fc91
DA
2594 goto out;
2595 }
2596
1e28fe0a
SF
2597 evlist__for_each(session->evlist, evsel) {
2598 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2599 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2600 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2601 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2602 evsel->handler = trace__pgfault;
2603 }
2604
bdc89661
DA
2605 err = parse_target_str(trace);
2606 if (err != 0)
2607 goto out;
2608
6810fc91
DA
2609 setup_pager();
2610
b7b61cbe 2611 err = perf_session__process_events(session);
6810fc91
DA
2612 if (err)
2613 pr_err("Failed to process events, error %d", err);
2614
bf2575c1
DA
2615 else if (trace->summary)
2616 trace__fprintf_thread_summary(trace, trace->output);
2617
6810fc91
DA
2618out:
2619 perf_session__delete(session);
2620
2621 return err;
2622}
2623
1302d88e
ACM
2624static size_t trace__fprintf_threads_header(FILE *fp)
2625{
2626 size_t printed;
2627
99ff7150 2628 printed = fprintf(fp, "\n Summary of events:\n\n");
bf2575c1
DA
2629
2630 return printed;
2631}
2632
2633static size_t thread__dump_stats(struct thread_trace *ttrace,
2634 struct trace *trace, FILE *fp)
2635{
2636 struct stats *stats;
2637 size_t printed = 0;
2638 struct syscall *sc;
2639 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2640
2641 if (inode == NULL)
2642 return 0;
2643
2644 printed += fprintf(fp, "\n");
2645
27a778b5
PE
2646 printed += fprintf(fp, " syscall calls min avg max stddev\n");
2647 printed += fprintf(fp, " (msec) (msec) (msec) (%%)\n");
2648 printed += fprintf(fp, " --------------- -------- --------- --------- --------- ------\n");
99ff7150 2649
bf2575c1
DA
2650 /* each int_node is a syscall */
2651 while (inode) {
2652 stats = inode->priv;
2653 if (stats) {
2654 double min = (double)(stats->min) / NSEC_PER_MSEC;
2655 double max = (double)(stats->max) / NSEC_PER_MSEC;
2656 double avg = avg_stats(stats);
2657 double pct;
2658 u64 n = (u64) stats->n;
2659
2660 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2661 avg /= NSEC_PER_MSEC;
2662
2663 sc = &trace->syscalls.table[inode->i];
99ff7150 2664 printed += fprintf(fp, " %-15s", sc->name);
27a778b5 2665 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f",
7f7a4138 2666 n, min, avg);
27a778b5 2667 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
bf2575c1
DA
2668 }
2669
2670 inode = intlist__next(inode);
2671 }
2672
2673 printed += fprintf(fp, "\n\n");
1302d88e
ACM
2674
2675 return printed;
2676}
2677
896cbb56
DA
2678/* struct used to pass data to per-thread function */
2679struct summary_data {
2680 FILE *fp;
2681 struct trace *trace;
2682 size_t printed;
2683};
2684
2685static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2686{
2687 struct summary_data *data = priv;
2688 FILE *fp = data->fp;
2689 size_t printed = data->printed;
2690 struct trace *trace = data->trace;
89dceb22 2691 struct thread_trace *ttrace = thread__priv(thread);
896cbb56
DA
2692 double ratio;
2693
2694 if (ttrace == NULL)
2695 return 0;
2696
2697 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2698
15e65c69 2699 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
99ff7150 2700 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
15e65c69 2701 printed += fprintf(fp, "%.1f%%", ratio);
a2ea67d7
SF
2702 if (ttrace->pfmaj)
2703 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2704 if (ttrace->pfmin)
2705 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
99ff7150 2706 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
bf2575c1 2707 printed += thread__dump_stats(ttrace, trace, fp);
896cbb56
DA
2708
2709 data->printed += printed;
2710
2711 return 0;
2712}
2713
1302d88e
ACM
2714static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2715{
896cbb56
DA
2716 struct summary_data data = {
2717 .fp = fp,
2718 .trace = trace
2719 };
2720 data.printed = trace__fprintf_threads_header(fp);
1302d88e 2721
896cbb56
DA
2722 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
2723
2724 return data.printed;
1302d88e
ACM
2725}
2726
ae9ed035
ACM
2727static int trace__set_duration(const struct option *opt, const char *str,
2728 int unset __maybe_unused)
2729{
2730 struct trace *trace = opt->value;
2731
2732 trace->duration_filter = atof(str);
2733 return 0;
2734}
2735
f078c385
ACM
2736static int trace__set_filter_pids(const struct option *opt, const char *str,
2737 int unset __maybe_unused)
2738{
2739 int ret = -1;
2740 size_t i;
2741 struct trace *trace = opt->value;
2742 /*
2743 * FIXME: introduce a intarray class, plain parse csv and create a
2744 * { int nr, int entries[] } struct...
2745 */
2746 struct intlist *list = intlist__new(str);
2747
2748 if (list == NULL)
2749 return -1;
2750
2751 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2752 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2753
2754 if (trace->filter_pids.entries == NULL)
2755 goto out;
2756
2757 trace->filter_pids.entries[0] = getpid();
2758
2759 for (i = 1; i < trace->filter_pids.nr; ++i)
2760 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2761
2762 intlist__delete(list);
2763 ret = 0;
2764out:
2765 return ret;
2766}
2767
c24ff998
ACM
2768static int trace__open_output(struct trace *trace, const char *filename)
2769{
2770 struct stat st;
2771
2772 if (!stat(filename, &st) && st.st_size) {
2773 char oldname[PATH_MAX];
2774
2775 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2776 unlink(oldname);
2777 rename(filename, oldname);
2778 }
2779
2780 trace->output = fopen(filename, "w");
2781
2782 return trace->output == NULL ? -errno : 0;
2783}
2784
598d02c5
SF
2785static int parse_pagefaults(const struct option *opt, const char *str,
2786 int unset __maybe_unused)
2787{
2788 int *trace_pgfaults = opt->value;
2789
2790 if (strcmp(str, "all") == 0)
2791 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2792 else if (strcmp(str, "maj") == 0)
2793 *trace_pgfaults |= TRACE_PFMAJ;
2794 else if (strcmp(str, "min") == 0)
2795 *trace_pgfaults |= TRACE_PFMIN;
2796 else
2797 return -1;
2798
2799 return 0;
2800}
2801
14a052df
ACM
2802static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2803{
2804 struct perf_evsel *evsel;
2805
2806 evlist__for_each(evlist, evsel)
2807 evsel->handler = handler;
2808}
2809
514f1c67
ACM
2810int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2811{
6fdd9cb7 2812 const char *trace_usage[] = {
f15eb531
NK
2813 "perf trace [<options>] [<command>]",
2814 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
2815 "perf trace record [<options>] [<command>]",
2816 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
2817 NULL
2818 };
2819 struct trace trace = {
c522739d
ACM
2820 .audit = {
2821 .machine = audit_detect_machine(),
2822 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2823 },
514f1c67
ACM
2824 .syscalls = {
2825 . max = -1,
2826 },
2827 .opts = {
2828 .target = {
2829 .uid = UINT_MAX,
2830 .uses_mmap = true,
2831 },
2832 .user_freq = UINT_MAX,
2833 .user_interval = ULLONG_MAX,
509051ea 2834 .no_buffering = true,
38d5447d 2835 .mmap_pages = UINT_MAX,
9d9cad76 2836 .proc_map_timeout = 500,
514f1c67 2837 },
c24ff998 2838 .output = stdout,
50c95cbd 2839 .show_comm = true,
e281a960 2840 .trace_syscalls = true,
514f1c67 2841 };
c24ff998 2842 const char *output_name = NULL;
2ae3a312 2843 const char *ev_qualifier_str = NULL;
514f1c67 2844 const struct option trace_options[] = {
14a052df
ACM
2845 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2846 "event selector. use 'perf list' to list available events",
2847 parse_events_option),
50c95cbd
ACM
2848 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2849 "show the thread COMM next to its id"),
c522739d 2850 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
d303e85a 2851 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
c24ff998 2852 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 2853 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
2854 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2855 "trace events on existing process id"),
ac9be8ee 2856 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 2857 "trace events on existing thread id"),
fa0e4ffe
ACM
2858 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
2859 "pids to filter (by the kernel)", trace__set_filter_pids),
ac9be8ee 2860 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 2861 "system-wide collection from all CPUs"),
ac9be8ee 2862 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 2863 "list of cpus to monitor"),
6810fc91 2864 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 2865 "child tasks do not inherit counters"),
994a1f78
JO
2866 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2867 "number of mmap data pages",
2868 perf_evlist__parse_mmap_pages),
ac9be8ee 2869 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 2870 "user to profile"),
ae9ed035
ACM
2871 OPT_CALLBACK(0, "duration", &trace, "float",
2872 "show only events with duration > N.M ms",
2873 trace__set_duration),
1302d88e 2874 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 2875 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
2876 OPT_BOOLEAN('T', "time", &trace.full_time,
2877 "Show full timestamp, not time relative to first start"),
fd2eabaf
DA
2878 OPT_BOOLEAN('s', "summary", &trace.summary_only,
2879 "Show only syscall summary with statistics"),
2880 OPT_BOOLEAN('S', "with-summary", &trace.summary,
2881 "Show all syscalls and summary with statistics"),
598d02c5
SF
2882 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
2883 "Trace pagefaults", parse_pagefaults, "maj"),
e281a960 2884 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
e366a6d8 2885 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
9d9cad76
KL
2886 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
2887 "per thread proc mmap processing timeout in ms"),
514f1c67
ACM
2888 OPT_END()
2889 };
6fdd9cb7 2890 const char * const trace_subcommands[] = { "record", NULL };
514f1c67 2891 int err;
32caf0d1 2892 char bf[BUFSIZ];
514f1c67 2893
4d08cb80
ACM
2894 signal(SIGSEGV, sighandler_dump_stack);
2895 signal(SIGFPE, sighandler_dump_stack);
2896
14a052df 2897 trace.evlist = perf_evlist__new();
14a052df
ACM
2898
2899 if (trace.evlist == NULL) {
2900 pr_err("Not enough memory to run!\n");
ff8f695c 2901 err = -ENOMEM;
14a052df
ACM
2902 goto out;
2903 }
2904
6fdd9cb7
YS
2905 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
2906 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
fd2eabaf 2907
598d02c5
SF
2908 if (trace.trace_pgfaults) {
2909 trace.opts.sample_address = true;
2910 trace.opts.sample_time = true;
2911 }
2912
14a052df
ACM
2913 if (trace.evlist->nr_entries > 0)
2914 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
2915
1e28fe0a
SF
2916 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
2917 return trace__record(&trace, argc-1, &argv[1]);
2918
2919 /* summary_only implies summary option, but don't overwrite summary if set */
2920 if (trace.summary_only)
2921 trace.summary = trace.summary_only;
2922
726f3234
ACM
2923 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
2924 trace.evlist->nr_entries == 0 /* Was --events used? */) {
e281a960
SF
2925 pr_err("Please specify something to trace.\n");
2926 return -1;
2927 }
2928
c24ff998
ACM
2929 if (output_name != NULL) {
2930 err = trace__open_output(&trace, output_name);
2931 if (err < 0) {
2932 perror("failed to create output file");
2933 goto out;
2934 }
2935 }
2936
2ae3a312 2937 if (ev_qualifier_str != NULL) {
b059efdf 2938 const char *s = ev_qualifier_str;
005438a8
ACM
2939 struct strlist_config slist_config = {
2940 .dirname = system_path(STRACE_GROUPS_DIR),
2941 };
b059efdf
ACM
2942
2943 trace.not_ev_qualifier = *s == '!';
2944 if (trace.not_ev_qualifier)
2945 ++s;
005438a8 2946 trace.ev_qualifier = strlist__new(s, &slist_config);
2ae3a312 2947 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
2948 fputs("Not enough memory to parse event qualifier",
2949 trace.output);
2950 err = -ENOMEM;
2951 goto out_close;
2ae3a312 2952 }
d0cc439b
ACM
2953
2954 err = trace__validate_ev_qualifier(&trace);
2955 if (err)
2956 goto out_close;
2ae3a312
ACM
2957 }
2958
602ad878 2959 err = target__validate(&trace.opts.target);
32caf0d1 2960 if (err) {
602ad878 2961 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2962 fprintf(trace.output, "%s", bf);
2963 goto out_close;
32caf0d1
NK
2964 }
2965
602ad878 2966 err = target__parse_uid(&trace.opts.target);
514f1c67 2967 if (err) {
602ad878 2968 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2969 fprintf(trace.output, "%s", bf);
2970 goto out_close;
514f1c67
ACM
2971 }
2972
602ad878 2973 if (!argc && target__none(&trace.opts.target))
ee76120e
NK
2974 trace.opts.target.system_wide = true;
2975
6810fc91
DA
2976 if (input_name)
2977 err = trace__replay(&trace);
2978 else
2979 err = trace__run(&trace, argc, argv);
1302d88e 2980
c24ff998
ACM
2981out_close:
2982 if (output_name != NULL)
2983 fclose(trace.output);
2984out:
1302d88e 2985 return err;
514f1c67 2986}