perf trace: Use the FD beautifier for socket syscall fds
[deliverable/linux.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",
28ebb87c
ACM
602 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE", "BOOTTIME",
603 "REALTIME_ALARM", "BOOTTIME_ALARM", "SGI_CYCLE", "TAI"
4f8c1b74
DA
604};
605static DEFINE_STRARRAY(clockid);
606
e10bce81
ACM
607static const char *socket_families[] = {
608 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
609 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
610 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
611 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
612 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
613 "ALG", "NFC", "VSOCK",
614};
615static DEFINE_STRARRAY(socket_families);
616
a28b24b2
ACM
617#ifndef SOCK_TYPE_MASK
618#define SOCK_TYPE_MASK 0xf
619#endif
620
621static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
622 struct syscall_arg *arg)
623{
624 size_t printed;
625 int type = arg->val,
626 flags = type & ~SOCK_TYPE_MASK;
627
628 type &= SOCK_TYPE_MASK;
629 /*
630 * Can't use a strarray, MIPS may override for ABI reasons.
631 */
632 switch (type) {
633#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
634 P_SK_TYPE(STREAM);
635 P_SK_TYPE(DGRAM);
636 P_SK_TYPE(RAW);
637 P_SK_TYPE(RDM);
638 P_SK_TYPE(SEQPACKET);
639 P_SK_TYPE(DCCP);
640 P_SK_TYPE(PACKET);
641#undef P_SK_TYPE
642 default:
643 printed = scnprintf(bf, size, "%#x", type);
644 }
645
646#define P_SK_FLAG(n) \
647 if (flags & SOCK_##n) { \
648 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
649 flags &= ~SOCK_##n; \
650 }
651
652 P_SK_FLAG(CLOEXEC);
653 P_SK_FLAG(NONBLOCK);
654#undef P_SK_FLAG
655
656 if (flags)
657 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
658
659 return printed;
660}
661
662#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
663
b2cc99fd
ACM
664#ifndef MSG_PROBE
665#define MSG_PROBE 0x10
666#endif
b6e8f8f4
DA
667#ifndef MSG_WAITFORONE
668#define MSG_WAITFORONE 0x10000
669#endif
b2cc99fd
ACM
670#ifndef MSG_SENDPAGE_NOTLAST
671#define MSG_SENDPAGE_NOTLAST 0x20000
672#endif
673#ifndef MSG_FASTOPEN
674#define MSG_FASTOPEN 0x20000000
675#endif
676
677static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
678 struct syscall_arg *arg)
679{
680 int printed = 0, flags = arg->val;
681
682 if (flags == 0)
683 return scnprintf(bf, size, "NONE");
684#define P_MSG_FLAG(n) \
685 if (flags & MSG_##n) { \
686 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
687 flags &= ~MSG_##n; \
688 }
689
690 P_MSG_FLAG(OOB);
691 P_MSG_FLAG(PEEK);
692 P_MSG_FLAG(DONTROUTE);
693 P_MSG_FLAG(TRYHARD);
694 P_MSG_FLAG(CTRUNC);
695 P_MSG_FLAG(PROBE);
696 P_MSG_FLAG(TRUNC);
697 P_MSG_FLAG(DONTWAIT);
698 P_MSG_FLAG(EOR);
699 P_MSG_FLAG(WAITALL);
700 P_MSG_FLAG(FIN);
701 P_MSG_FLAG(SYN);
702 P_MSG_FLAG(CONFIRM);
703 P_MSG_FLAG(RST);
704 P_MSG_FLAG(ERRQUEUE);
705 P_MSG_FLAG(NOSIGNAL);
706 P_MSG_FLAG(MORE);
707 P_MSG_FLAG(WAITFORONE);
708 P_MSG_FLAG(SENDPAGE_NOTLAST);
709 P_MSG_FLAG(FASTOPEN);
710 P_MSG_FLAG(CMSG_CLOEXEC);
711#undef P_MSG_FLAG
712
713 if (flags)
714 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
715
716 return printed;
717}
718
719#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
720
51108999
ACM
721static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
722 struct syscall_arg *arg)
723{
724 size_t printed = 0;
725 int mode = arg->val;
726
727 if (mode == F_OK) /* 0 */
728 return scnprintf(bf, size, "F");
729#define P_MODE(n) \
730 if (mode & n##_OK) { \
731 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
732 mode &= ~n##_OK; \
733 }
734
735 P_MODE(R);
736 P_MODE(W);
737 P_MODE(X);
738#undef P_MODE
739
740 if (mode)
741 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
742
743 return printed;
744}
745
746#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
747
f994592d
ACM
748static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
749 struct syscall_arg *arg);
750
751#define SCA_FILENAME syscall_arg__scnprintf_filename
752
be65a89a 753static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
01533e97 754 struct syscall_arg *arg)
be65a89a 755{
01533e97 756 int printed = 0, flags = arg->val;
be65a89a
ACM
757
758 if (!(flags & O_CREAT))
01533e97 759 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
be65a89a
ACM
760
761 if (flags == 0)
762 return scnprintf(bf, size, "RDONLY");
763#define P_FLAG(n) \
764 if (flags & O_##n) { \
765 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
766 flags &= ~O_##n; \
767 }
768
769 P_FLAG(APPEND);
770 P_FLAG(ASYNC);
771 P_FLAG(CLOEXEC);
772 P_FLAG(CREAT);
773 P_FLAG(DIRECT);
774 P_FLAG(DIRECTORY);
775 P_FLAG(EXCL);
776 P_FLAG(LARGEFILE);
777 P_FLAG(NOATIME);
778 P_FLAG(NOCTTY);
779#ifdef O_NONBLOCK
780 P_FLAG(NONBLOCK);
781#elif O_NDELAY
782 P_FLAG(NDELAY);
783#endif
784#ifdef O_PATH
785 P_FLAG(PATH);
786#endif
787 P_FLAG(RDWR);
788#ifdef O_DSYNC
789 if ((flags & O_SYNC) == O_SYNC)
790 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
791 else {
792 P_FLAG(DSYNC);
793 }
794#else
795 P_FLAG(SYNC);
796#endif
797 P_FLAG(TRUNC);
798 P_FLAG(WRONLY);
799#undef P_FLAG
800
801 if (flags)
802 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
803
804 return printed;
805}
806
807#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
808
a1c2552d
ACM
809static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
810 struct syscall_arg *arg)
811{
812 int printed = 0, flags = arg->val;
813
814 if (flags == 0)
815 return 0;
816
817#define P_FLAG(n) \
818 if (flags & PERF_FLAG_##n) { \
819 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
820 flags &= ~PERF_FLAG_##n; \
821 }
822
823 P_FLAG(FD_NO_GROUP);
824 P_FLAG(FD_OUTPUT);
825 P_FLAG(PID_CGROUP);
826 P_FLAG(FD_CLOEXEC);
827#undef P_FLAG
828
829 if (flags)
830 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
831
832 return printed;
833}
834
835#define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
836
49af9e93
ACM
837static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
838 struct syscall_arg *arg)
839{
840 int printed = 0, flags = arg->val;
841
842 if (flags == 0)
843 return scnprintf(bf, size, "NONE");
844#define P_FLAG(n) \
845 if (flags & EFD_##n) { \
846 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
847 flags &= ~EFD_##n; \
848 }
849
850 P_FLAG(SEMAPHORE);
851 P_FLAG(CLOEXEC);
852 P_FLAG(NONBLOCK);
853#undef P_FLAG
854
855 if (flags)
856 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
857
858 return printed;
859}
860
861#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
862
46cce19b
ACM
863static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
864 struct syscall_arg *arg)
865{
866 int printed = 0, flags = arg->val;
867
868#define P_FLAG(n) \
869 if (flags & O_##n) { \
870 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
871 flags &= ~O_##n; \
872 }
873
874 P_FLAG(CLOEXEC);
875 P_FLAG(NONBLOCK);
876#undef P_FLAG
877
878 if (flags)
879 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
880
881 return printed;
882}
883
884#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
885
8bad5b0a
ACM
886static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
887{
888 int sig = arg->val;
889
890 switch (sig) {
891#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
892 P_SIGNUM(HUP);
893 P_SIGNUM(INT);
894 P_SIGNUM(QUIT);
895 P_SIGNUM(ILL);
896 P_SIGNUM(TRAP);
897 P_SIGNUM(ABRT);
898 P_SIGNUM(BUS);
899 P_SIGNUM(FPE);
900 P_SIGNUM(KILL);
901 P_SIGNUM(USR1);
902 P_SIGNUM(SEGV);
903 P_SIGNUM(USR2);
904 P_SIGNUM(PIPE);
905 P_SIGNUM(ALRM);
906 P_SIGNUM(TERM);
8bad5b0a
ACM
907 P_SIGNUM(CHLD);
908 P_SIGNUM(CONT);
909 P_SIGNUM(STOP);
910 P_SIGNUM(TSTP);
911 P_SIGNUM(TTIN);
912 P_SIGNUM(TTOU);
913 P_SIGNUM(URG);
914 P_SIGNUM(XCPU);
915 P_SIGNUM(XFSZ);
916 P_SIGNUM(VTALRM);
917 P_SIGNUM(PROF);
918 P_SIGNUM(WINCH);
919 P_SIGNUM(IO);
920 P_SIGNUM(PWR);
921 P_SIGNUM(SYS);
02c5bb4a
BH
922#ifdef SIGEMT
923 P_SIGNUM(EMT);
924#endif
925#ifdef SIGSTKFLT
926 P_SIGNUM(STKFLT);
927#endif
928#ifdef SIGSWI
929 P_SIGNUM(SWI);
930#endif
8bad5b0a
ACM
931 default: break;
932 }
933
934 return scnprintf(bf, size, "%#x", sig);
935}
936
937#define SCA_SIGNUM syscall_arg__scnprintf_signum
938
844ae5b4
ACM
939#if defined(__i386__) || defined(__x86_64__)
940/*
941 * FIXME: Make this available to all arches.
942 */
78645cf3
ACM
943#define TCGETS 0x5401
944
945static const char *tioctls[] = {
946 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
947 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
948 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
949 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
950 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
951 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
952 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
953 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
954 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
955 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
956 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
957 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
958 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
959 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
960 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
961};
962
963static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
844ae5b4 964#endif /* defined(__i386__) || defined(__x86_64__) */
78645cf3 965
453350dd
ACM
966#define STRARRAY(arg, name, array) \
967 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
968 .arg_parm = { [arg] = &strarray__##array, }
969
514f1c67
ACM
970static struct syscall_fmt {
971 const char *name;
aec1930b 972 const char *alias;
01533e97 973 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 974 void *arg_parm[6];
514f1c67
ACM
975 bool errmsg;
976 bool timeout;
04b34729 977 bool hexret;
514f1c67 978} syscall_fmts[] = {
51108999 979 { .name = "access", .errmsg = true,
34221118
ACM
980 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
981 [1] = SCA_ACCMODE, /* mode */ }, },
aec1930b 982 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
beccb2b5
ACM
983 { .name = "brk", .hexret = true,
984 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
34221118
ACM
985 { .name = "chdir", .errmsg = true,
986 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
987 { .name = "chmod", .errmsg = true,
988 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
989 { .name = "chroot", .errmsg = true,
990 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
4f8c1b74 991 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
75b757ca 992 { .name = "close", .errmsg = true,
48000a1a 993 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
a14bb860 994 { .name = "connect", .errmsg = true, },
34221118
ACM
995 { .name = "creat", .errmsg = true,
996 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 997 { .name = "dup", .errmsg = true,
48000a1a 998 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 999 { .name = "dup2", .errmsg = true,
48000a1a 1000 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1001 { .name = "dup3", .errmsg = true,
48000a1a 1002 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1003 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
49af9e93
ACM
1004 { .name = "eventfd2", .errmsg = true,
1005 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
75b757ca 1006 { .name = "faccessat", .errmsg = true,
34221118
ACM
1007 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1008 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1009 { .name = "fadvise64", .errmsg = true,
48000a1a 1010 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1011 { .name = "fallocate", .errmsg = true,
48000a1a 1012 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1013 { .name = "fchdir", .errmsg = true,
48000a1a 1014 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1015 { .name = "fchmod", .errmsg = true,
48000a1a 1016 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1017 { .name = "fchmodat", .errmsg = true,
090389b6
ACM
1018 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1019 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1020 { .name = "fchown", .errmsg = true,
48000a1a 1021 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1022 { .name = "fchownat", .errmsg = true,
34221118
ACM
1023 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1024 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca
ACM
1025 { .name = "fcntl", .errmsg = true,
1026 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1027 [1] = SCA_STRARRAY, /* cmd */ },
1028 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
1029 { .name = "fdatasync", .errmsg = true,
48000a1a 1030 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
5cea6ff2 1031 { .name = "flock", .errmsg = true,
75b757ca
ACM
1032 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1033 [1] = SCA_FLOCK, /* cmd */ }, },
1034 { .name = "fsetxattr", .errmsg = true,
48000a1a 1035 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1036 { .name = "fstat", .errmsg = true, .alias = "newfstat",
48000a1a 1037 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1038 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
34221118
ACM
1039 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1040 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1041 { .name = "fstatfs", .errmsg = true,
48000a1a 1042 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1043 { .name = "fsync", .errmsg = true,
48000a1a 1044 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1045 { .name = "ftruncate", .errmsg = true,
48000a1a 1046 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
f9da0b0c
ACM
1047 { .name = "futex", .errmsg = true,
1048 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
75b757ca 1049 { .name = "futimesat", .errmsg = true,
090389b6
ACM
1050 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1051 [1] = SCA_FILENAME, /* filename */ }, },
75b757ca 1052 { .name = "getdents", .errmsg = true,
48000a1a 1053 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1054 { .name = "getdents64", .errmsg = true,
48000a1a 1055 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd
ACM
1056 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1057 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
34221118
ACM
1058 { .name = "getxattr", .errmsg = true,
1059 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1060 { .name = "inotify_add_watch", .errmsg = true,
1061 .arg_scnprintf = { [1] = SCA_FILENAME, /* pathname */ }, },
beccb2b5 1062 { .name = "ioctl", .errmsg = true,
48000a1a 1063 .arg_scnprintf = { [0] = SCA_FD, /* fd */
844ae5b4
ACM
1064#if defined(__i386__) || defined(__x86_64__)
1065/*
1066 * FIXME: Make this available to all arches.
1067 */
78645cf3
ACM
1068 [1] = SCA_STRHEXARRAY, /* cmd */
1069 [2] = SCA_HEX, /* arg */ },
1070 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
844ae5b4
ACM
1071#else
1072 [2] = SCA_HEX, /* arg */ }, },
1073#endif
8bad5b0a
ACM
1074 { .name = "kill", .errmsg = true,
1075 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
34221118
ACM
1076 { .name = "lchown", .errmsg = true,
1077 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
1078 { .name = "lgetxattr", .errmsg = true,
1079 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1080 { .name = "linkat", .errmsg = true,
48000a1a 1081 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
34221118
ACM
1082 { .name = "listxattr", .errmsg = true,
1083 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
090389b6
ACM
1084 { .name = "llistxattr", .errmsg = true,
1085 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1086 { .name = "lremovexattr", .errmsg = true,
1087 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca
ACM
1088 { .name = "lseek", .errmsg = true,
1089 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1090 [2] = SCA_STRARRAY, /* whence */ },
1091 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
34221118
ACM
1092 { .name = "lsetxattr", .errmsg = true,
1093 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
090389b6
ACM
1094 { .name = "lstat", .errmsg = true, .alias = "newlstat",
1095 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
34221118
ACM
1096 { .name = "lsxattr", .errmsg = true,
1097 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
9e9716d1
ACM
1098 { .name = "madvise", .errmsg = true,
1099 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1100 [2] = SCA_MADV_BHV, /* behavior */ }, },
34221118
ACM
1101 { .name = "mkdir", .errmsg = true,
1102 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1103 { .name = "mkdirat", .errmsg = true,
34221118
ACM
1104 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1105 [1] = SCA_FILENAME, /* pathname */ }, },
1106 { .name = "mknod", .errmsg = true,
1107 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
75b757ca 1108 { .name = "mknodat", .errmsg = true,
090389b6
ACM
1109 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */
1110 [1] = SCA_FILENAME, /* filename */ }, },
3d903aa7
ACM
1111 { .name = "mlock", .errmsg = true,
1112 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
1113 { .name = "mlockall", .errmsg = true,
1114 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5 1115 { .name = "mmap", .hexret = true,
ae685380 1116 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
941557e0 1117 [2] = SCA_MMAP_PROT, /* prot */
73faab3a
NK
1118 [3] = SCA_MMAP_FLAGS, /* flags */
1119 [4] = SCA_FD, /* fd */ }, },
beccb2b5 1120 { .name = "mprotect", .errmsg = true,
ae685380
ACM
1121 .arg_scnprintf = { [0] = SCA_HEX, /* start */
1122 [2] = SCA_MMAP_PROT, /* prot */ }, },
090389b6
ACM
1123 { .name = "mq_unlink", .errmsg = true,
1124 .arg_scnprintf = { [0] = SCA_FILENAME, /* u_name */ }, },
ae685380
ACM
1125 { .name = "mremap", .hexret = true,
1126 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
86998dda 1127 [3] = SCA_MREMAP_FLAGS, /* flags */
ae685380 1128 [4] = SCA_HEX, /* new_addr */ }, },
3d903aa7
ACM
1129 { .name = "munlock", .errmsg = true,
1130 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5
ACM
1131 { .name = "munmap", .errmsg = true,
1132 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
75b757ca 1133 { .name = "name_to_handle_at", .errmsg = true,
48000a1a 1134 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
75b757ca 1135 { .name = "newfstatat", .errmsg = true,
34221118
ACM
1136 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1137 [1] = SCA_FILENAME, /* filename */ }, },
be65a89a 1138 { .name = "open", .errmsg = true,
f994592d
ACM
1139 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */
1140 [1] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1141 { .name = "open_by_handle_at", .errmsg = true,
75b757ca
ACM
1142 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1143 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 1144 { .name = "openat", .errmsg = true,
75b757ca 1145 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
34221118 1146 [1] = SCA_FILENAME, /* filename */
75b757ca 1147 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
a1c2552d
ACM
1148 { .name = "perf_event_open", .errmsg = true,
1149 .arg_scnprintf = { [1] = SCA_INT, /* pid */
1150 [2] = SCA_INT, /* cpu */
1151 [3] = SCA_FD, /* group_fd */
1152 [4] = SCA_PERF_FLAGS, /* flags */ }, },
46cce19b
ACM
1153 { .name = "pipe2", .errmsg = true,
1154 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
aec1930b
ACM
1155 { .name = "poll", .errmsg = true, .timeout = true, },
1156 { .name = "ppoll", .errmsg = true, .timeout = true, },
75b757ca 1157 { .name = "pread", .errmsg = true, .alias = "pread64",
48000a1a 1158 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1159 { .name = "preadv", .errmsg = true, .alias = "pread",
48000a1a 1160 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 1161 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
75b757ca 1162 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
48000a1a 1163 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1164 { .name = "pwritev", .errmsg = true,
48000a1a 1165 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1166 { .name = "read", .errmsg = true,
48000a1a 1167 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
34221118
ACM
1168 { .name = "readlink", .errmsg = true,
1169 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
75b757ca 1170 { .name = "readlinkat", .errmsg = true,
34221118
ACM
1171 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1172 [1] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1173 { .name = "readv", .errmsg = true,
48000a1a 1174 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
b2cc99fd 1175 { .name = "recvfrom", .errmsg = true,
8d8c66a2
ACM
1176 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1177 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1178 { .name = "recvmmsg", .errmsg = true,
8d8c66a2
ACM
1179 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1180 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1181 { .name = "recvmsg", .errmsg = true,
8d8c66a2
ACM
1182 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1183 [2] = SCA_MSG_FLAGS, /* flags */ }, },
34221118
ACM
1184 { .name = "removexattr", .errmsg = true,
1185 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1186 { .name = "renameat", .errmsg = true,
48000a1a 1187 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
34221118
ACM
1188 { .name = "rmdir", .errmsg = true,
1189 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
8bad5b0a
ACM
1190 { .name = "rt_sigaction", .errmsg = true,
1191 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
453350dd 1192 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
8bad5b0a
ACM
1193 { .name = "rt_sigqueueinfo", .errmsg = true,
1194 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
1195 { .name = "rt_tgsigqueueinfo", .errmsg = true,
1196 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
aec1930b 1197 { .name = "select", .errmsg = true, .timeout = true, },
b2cc99fd 1198 { .name = "sendmmsg", .errmsg = true,
8d8c66a2
ACM
1199 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1200 [3] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1201 { .name = "sendmsg", .errmsg = true,
8d8c66a2
ACM
1202 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1203 [2] = SCA_MSG_FLAGS, /* flags */ }, },
b2cc99fd 1204 { .name = "sendto", .errmsg = true,
8d8c66a2
ACM
1205 .arg_scnprintf = { [0] = SCA_FD, /* fd */
1206 [3] = SCA_MSG_FLAGS, /* flags */ }, },
453350dd
ACM
1207 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
1208 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
34221118
ACM
1209 { .name = "setxattr", .errmsg = true,
1210 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
75b757ca 1211 { .name = "shutdown", .errmsg = true,
48000a1a 1212 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
e10bce81 1213 { .name = "socket", .errmsg = true,
a28b24b2
ACM
1214 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1215 [1] = SCA_SK_TYPE, /* type */ },
07120aa5
ACM
1216 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
1217 { .name = "socketpair", .errmsg = true,
1218 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
1219 [1] = SCA_SK_TYPE, /* type */ },
e10bce81 1220 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
090389b6
ACM
1221 { .name = "stat", .errmsg = true, .alias = "newstat",
1222 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
34221118
ACM
1223 { .name = "statfs", .errmsg = true,
1224 .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, },
1225 { .name = "swapoff", .errmsg = true,
1226 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
1227 { .name = "swapon", .errmsg = true,
1228 .arg_scnprintf = { [0] = SCA_FILENAME, /* specialfile */ }, },
75b757ca 1229 { .name = "symlinkat", .errmsg = true,
48000a1a 1230 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
1231 { .name = "tgkill", .errmsg = true,
1232 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
1233 { .name = "tkill", .errmsg = true,
1234 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
34221118
ACM
1235 { .name = "truncate", .errmsg = true,
1236 .arg_scnprintf = { [0] = SCA_FILENAME, /* path */ }, },
e5959683 1237 { .name = "uname", .errmsg = true, .alias = "newuname", },
75b757ca 1238 { .name = "unlinkat", .errmsg = true,
34221118
ACM
1239 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
1240 [1] = SCA_FILENAME, /* pathname */ }, },
1241 { .name = "utime", .errmsg = true,
1242 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
75b757ca 1243 { .name = "utimensat", .errmsg = true,
34221118
ACM
1244 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */
1245 [1] = SCA_FILENAME, /* filename */ }, },
1246 { .name = "utimes", .errmsg = true,
1247 .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, },
090389b6
ACM
1248 { .name = "vmsplice", .errmsg = true,
1249 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1250 { .name = "write", .errmsg = true,
48000a1a 1251 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
75b757ca 1252 { .name = "writev", .errmsg = true,
48000a1a 1253 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
514f1c67
ACM
1254};
1255
1256static int syscall_fmt__cmp(const void *name, const void *fmtp)
1257{
1258 const struct syscall_fmt *fmt = fmtp;
1259 return strcmp(name, fmt->name);
1260}
1261
1262static struct syscall_fmt *syscall_fmt__find(const char *name)
1263{
1264 const int nmemb = ARRAY_SIZE(syscall_fmts);
1265 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
1266}
1267
1268struct syscall {
1269 struct event_format *tp_format;
f208bd8d
ACM
1270 int nr_args;
1271 struct format_field *args;
514f1c67 1272 const char *name;
5089f20e 1273 bool is_exit;
514f1c67 1274 struct syscall_fmt *fmt;
01533e97 1275 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 1276 void **arg_parm;
514f1c67
ACM
1277};
1278
60c907ab
ACM
1279static size_t fprintf_duration(unsigned long t, FILE *fp)
1280{
1281 double duration = (double)t / NSEC_PER_MSEC;
1282 size_t printed = fprintf(fp, "(");
1283
1284 if (duration >= 1.0)
1285 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
1286 else if (duration >= 0.01)
1287 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
1288 else
1289 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
c24ff998 1290 return printed + fprintf(fp, "): ");
60c907ab
ACM
1291}
1292
f994592d
ACM
1293/**
1294 * filename.ptr: The filename char pointer that will be vfs_getname'd
1295 * filename.entry_str_pos: Where to insert the string translated from
1296 * filename.ptr by the vfs_getname tracepoint/kprobe.
1297 */
752fde44
ACM
1298struct thread_trace {
1299 u64 entry_time;
1300 u64 exit_time;
1301 bool entry_pending;
efd5745e 1302 unsigned long nr_events;
a2ea67d7 1303 unsigned long pfmaj, pfmin;
752fde44 1304 char *entry_str;
1302d88e 1305 double runtime_ms;
f994592d
ACM
1306 struct {
1307 unsigned long ptr;
1308 int entry_str_pos;
1309 } filename;
75b757ca
ACM
1310 struct {
1311 int max;
1312 char **table;
1313 } paths;
bf2575c1
DA
1314
1315 struct intlist *syscall_stats;
752fde44
ACM
1316};
1317
1318static struct thread_trace *thread_trace__new(void)
1319{
75b757ca
ACM
1320 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
1321
1322 if (ttrace)
1323 ttrace->paths.max = -1;
1324
bf2575c1
DA
1325 ttrace->syscall_stats = intlist__new(NULL);
1326
75b757ca 1327 return ttrace;
752fde44
ACM
1328}
1329
c24ff998 1330static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
752fde44 1331{
efd5745e
ACM
1332 struct thread_trace *ttrace;
1333
752fde44
ACM
1334 if (thread == NULL)
1335 goto fail;
1336
89dceb22
NK
1337 if (thread__priv(thread) == NULL)
1338 thread__set_priv(thread, thread_trace__new());
48000a1a 1339
89dceb22 1340 if (thread__priv(thread) == NULL)
752fde44
ACM
1341 goto fail;
1342
89dceb22 1343 ttrace = thread__priv(thread);
efd5745e
ACM
1344 ++ttrace->nr_events;
1345
1346 return ttrace;
752fde44 1347fail:
c24ff998 1348 color_fprintf(fp, PERF_COLOR_RED,
752fde44
ACM
1349 "WARNING: not enough memory, dropping samples!\n");
1350 return NULL;
1351}
1352
598d02c5
SF
1353#define TRACE_PFMAJ (1 << 0)
1354#define TRACE_PFMIN (1 << 1)
1355
e4d44e83
ACM
1356static const size_t trace__entry_str_size = 2048;
1357
514f1c67 1358struct trace {
c24ff998 1359 struct perf_tool tool;
c522739d
ACM
1360 struct {
1361 int machine;
1362 int open_id;
1363 } audit;
514f1c67
ACM
1364 struct {
1365 int max;
1366 struct syscall *table;
c27366f0 1367 struct {
8b3ce757
ACM
1368 struct perf_evsel *sys_enter,
1369 *sys_exit;
c27366f0 1370 } events;
514f1c67 1371 } syscalls;
b4006796 1372 struct record_opts opts;
14a052df 1373 struct perf_evlist *evlist;
8fb598e5 1374 struct machine *host;
e596663e 1375 struct thread *current;
752fde44 1376 u64 base_time;
c24ff998 1377 FILE *output;
efd5745e 1378 unsigned long nr_events;
b059efdf 1379 struct strlist *ev_qualifier;
8b3ce757
ACM
1380 struct {
1381 size_t nr;
1382 int *entries;
1383 } ev_qualifier_ids;
c522739d 1384 const char *last_vfs_getname;
bdc89661
DA
1385 struct intlist *tid_list;
1386 struct intlist *pid_list;
f078c385
ACM
1387 struct {
1388 size_t nr;
1389 pid_t *entries;
1390 } filter_pids;
98eafce6
ACM
1391 double duration_filter;
1392 double runtime_ms;
1393 struct {
1394 u64 vfs_getname,
1395 proc_getname;
1396 } stats;
1397 bool not_ev_qualifier;
1398 bool live;
1399 bool full_time;
1302d88e 1400 bool sched;
752fde44 1401 bool multiple_threads;
bf2575c1 1402 bool summary;
fd2eabaf 1403 bool summary_only;
50c95cbd 1404 bool show_comm;
c522739d 1405 bool show_tool_stats;
e281a960 1406 bool trace_syscalls;
e366a6d8 1407 bool force;
08c98776 1408 bool vfs_getname;
598d02c5 1409 int trace_pgfaults;
514f1c67
ACM
1410};
1411
97119f37 1412static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
75b757ca 1413{
89dceb22 1414 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1415
1416 if (fd > ttrace->paths.max) {
1417 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
1418
1419 if (npath == NULL)
1420 return -1;
1421
1422 if (ttrace->paths.max != -1) {
1423 memset(npath + ttrace->paths.max + 1, 0,
1424 (fd - ttrace->paths.max) * sizeof(char *));
1425 } else {
1426 memset(npath, 0, (fd + 1) * sizeof(char *));
1427 }
1428
1429 ttrace->paths.table = npath;
1430 ttrace->paths.max = fd;
1431 }
1432
1433 ttrace->paths.table[fd] = strdup(pathname);
1434
1435 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1436}
1437
97119f37
ACM
1438static int thread__read_fd_path(struct thread *thread, int fd)
1439{
1440 char linkname[PATH_MAX], pathname[PATH_MAX];
1441 struct stat st;
1442 int ret;
1443
1444 if (thread->pid_ == thread->tid) {
1445 scnprintf(linkname, sizeof(linkname),
1446 "/proc/%d/fd/%d", thread->pid_, fd);
1447 } else {
1448 scnprintf(linkname, sizeof(linkname),
1449 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1450 }
1451
1452 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1453 return -1;
1454
1455 ret = readlink(linkname, pathname, sizeof(pathname));
1456
1457 if (ret < 0 || ret > st.st_size)
1458 return -1;
1459
1460 pathname[ret] = '\0';
1461 return trace__set_fd_pathname(thread, fd, pathname);
1462}
1463
c522739d
ACM
1464static const char *thread__fd_path(struct thread *thread, int fd,
1465 struct trace *trace)
75b757ca 1466{
89dceb22 1467 struct thread_trace *ttrace = thread__priv(thread);
75b757ca
ACM
1468
1469 if (ttrace == NULL)
1470 return NULL;
1471
1472 if (fd < 0)
1473 return NULL;
1474
cdcd1e6b 1475 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL)) {
c522739d
ACM
1476 if (!trace->live)
1477 return NULL;
1478 ++trace->stats.proc_getname;
cdcd1e6b 1479 if (thread__read_fd_path(thread, fd))
c522739d
ACM
1480 return NULL;
1481 }
75b757ca
ACM
1482
1483 return ttrace->paths.table[fd];
1484}
1485
1486static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1487 struct syscall_arg *arg)
1488{
1489 int fd = arg->val;
1490 size_t printed = scnprintf(bf, size, "%d", fd);
c522739d 1491 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
75b757ca
ACM
1492
1493 if (path)
1494 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1495
1496 return printed;
1497}
1498
1499static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1500 struct syscall_arg *arg)
1501{
1502 int fd = arg->val;
1503 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
89dceb22 1504 struct thread_trace *ttrace = thread__priv(arg->thread);
75b757ca 1505
04662523
ACM
1506 if (ttrace && fd >= 0 && fd <= ttrace->paths.max)
1507 zfree(&ttrace->paths.table[fd]);
75b757ca
ACM
1508
1509 return printed;
1510}
1511
f994592d
ACM
1512static void thread__set_filename_pos(struct thread *thread, const char *bf,
1513 unsigned long ptr)
1514{
1515 struct thread_trace *ttrace = thread__priv(thread);
1516
1517 ttrace->filename.ptr = ptr;
1518 ttrace->filename.entry_str_pos = bf - ttrace->entry_str;
1519}
1520
1521static size_t syscall_arg__scnprintf_filename(char *bf, size_t size,
1522 struct syscall_arg *arg)
1523{
1524 unsigned long ptr = arg->val;
1525
1526 if (!arg->trace->vfs_getname)
1527 return scnprintf(bf, size, "%#x", ptr);
1528
1529 thread__set_filename_pos(arg->thread, bf, ptr);
1530 return 0;
1531}
1532
ae9ed035
ACM
1533static bool trace__filter_duration(struct trace *trace, double t)
1534{
1535 return t < (trace->duration_filter * NSEC_PER_MSEC);
1536}
1537
752fde44
ACM
1538static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1539{
1540 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1541
60c907ab 1542 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
1543}
1544
f15eb531 1545static bool done = false;
ba209f85 1546static bool interrupted = false;
f15eb531 1547
ba209f85 1548static void sig_handler(int sig)
f15eb531
NK
1549{
1550 done = true;
ba209f85 1551 interrupted = sig == SIGINT;
f15eb531
NK
1552}
1553
752fde44 1554static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 1555 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
1556{
1557 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 1558 printed += fprintf_duration(duration, fp);
752fde44 1559
50c95cbd
ACM
1560 if (trace->multiple_threads) {
1561 if (trace->show_comm)
1902efe7 1562 printed += fprintf(fp, "%.14s/", thread__comm_str(thread));
38051234 1563 printed += fprintf(fp, "%d ", thread->tid);
50c95cbd 1564 }
752fde44
ACM
1565
1566 return printed;
1567}
1568
c24ff998 1569static int trace__process_event(struct trace *trace, struct machine *machine,
162f0bef 1570 union perf_event *event, struct perf_sample *sample)
752fde44
ACM
1571{
1572 int ret = 0;
1573
1574 switch (event->header.type) {
1575 case PERF_RECORD_LOST:
c24ff998 1576 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44 1577 "LOST %" PRIu64 " events!\n", event->lost.lost);
162f0bef 1578 ret = machine__process_lost_event(machine, event, sample);
752fde44 1579 default:
162f0bef 1580 ret = machine__process_event(machine, event, sample);
752fde44
ACM
1581 break;
1582 }
1583
1584 return ret;
1585}
1586
c24ff998 1587static int trace__tool_process(struct perf_tool *tool,
752fde44 1588 union perf_event *event,
162f0bef 1589 struct perf_sample *sample,
752fde44
ACM
1590 struct machine *machine)
1591{
c24ff998 1592 struct trace *trace = container_of(tool, struct trace, tool);
162f0bef 1593 return trace__process_event(trace, machine, event, sample);
752fde44
ACM
1594}
1595
1596static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1597{
0a7e6d1b 1598 int err = symbol__init(NULL);
752fde44
ACM
1599
1600 if (err)
1601 return err;
1602
8fb598e5
DA
1603 trace->host = machine__new_host();
1604 if (trace->host == NULL)
1605 return -ENOMEM;
752fde44 1606
959c2199 1607 if (trace_event__register_resolver(trace->host, machine__resolve_kernel_addr) < 0)
706c3da4
ACM
1608 return -errno;
1609
a33fbd56 1610 err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target,
9d9cad76
KL
1611 evlist->threads, trace__tool_process, false,
1612 trace->opts.proc_map_timeout);
752fde44
ACM
1613 if (err)
1614 symbol__exit();
1615
1616 return err;
1617}
1618
13d4ff3e
ACM
1619static int syscall__set_arg_fmts(struct syscall *sc)
1620{
1621 struct format_field *field;
1622 int idx = 0;
1623
f208bd8d 1624 sc->arg_scnprintf = calloc(sc->nr_args, sizeof(void *));
13d4ff3e
ACM
1625 if (sc->arg_scnprintf == NULL)
1626 return -1;
1627
1f115cb7
ACM
1628 if (sc->fmt)
1629 sc->arg_parm = sc->fmt->arg_parm;
1630
f208bd8d 1631 for (field = sc->args; field; field = field->next) {
beccb2b5
ACM
1632 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1633 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1634 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e
ACM
1635 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1636 ++idx;
1637 }
1638
1639 return 0;
1640}
1641
514f1c67
ACM
1642static int trace__read_syscall_info(struct trace *trace, int id)
1643{
1644 char tp_name[128];
1645 struct syscall *sc;
c522739d 1646 const char *name = audit_syscall_to_name(id, trace->audit.machine);
3a531260
ACM
1647
1648 if (name == NULL)
1649 return -1;
514f1c67
ACM
1650
1651 if (id > trace->syscalls.max) {
1652 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1653
1654 if (nsyscalls == NULL)
1655 return -1;
1656
1657 if (trace->syscalls.max != -1) {
1658 memset(nsyscalls + trace->syscalls.max + 1, 0,
1659 (id - trace->syscalls.max) * sizeof(*sc));
1660 } else {
1661 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1662 }
1663
1664 trace->syscalls.table = nsyscalls;
1665 trace->syscalls.max = id;
1666 }
1667
1668 sc = trace->syscalls.table + id;
3a531260 1669 sc->name = name;
2ae3a312 1670
3a531260 1671 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 1672
aec1930b 1673 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
97978b3e 1674 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b
ACM
1675
1676 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1677 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
97978b3e 1678 sc->tp_format = trace_event__tp_format("syscalls", tp_name);
aec1930b 1679 }
514f1c67 1680
13d4ff3e
ACM
1681 if (sc->tp_format == NULL)
1682 return -1;
1683
f208bd8d
ACM
1684 sc->args = sc->tp_format->format.fields;
1685 sc->nr_args = sc->tp_format->format.nr_fields;
1686 /* drop nr field - not relevant here; does not exist on older kernels */
1687 if (sc->args && strcmp(sc->args->name, "nr") == 0) {
1688 sc->args = sc->args->next;
1689 --sc->nr_args;
1690 }
1691
5089f20e
ACM
1692 sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit");
1693
13d4ff3e 1694 return syscall__set_arg_fmts(sc);
514f1c67
ACM
1695}
1696
d0cc439b
ACM
1697static int trace__validate_ev_qualifier(struct trace *trace)
1698{
8b3ce757 1699 int err = 0, i;
d0cc439b
ACM
1700 struct str_node *pos;
1701
8b3ce757
ACM
1702 trace->ev_qualifier_ids.nr = strlist__nr_entries(trace->ev_qualifier);
1703 trace->ev_qualifier_ids.entries = malloc(trace->ev_qualifier_ids.nr *
1704 sizeof(trace->ev_qualifier_ids.entries[0]));
1705
1706 if (trace->ev_qualifier_ids.entries == NULL) {
1707 fputs("Error:\tNot enough memory for allocating events qualifier ids\n",
1708 trace->output);
1709 err = -EINVAL;
1710 goto out;
1711 }
1712
1713 i = 0;
1714
d0cc439b
ACM
1715 strlist__for_each(pos, trace->ev_qualifier) {
1716 const char *sc = pos->s;
8b3ce757 1717 int id = audit_name_to_syscall(sc, trace->audit.machine);
d0cc439b 1718
8b3ce757 1719 if (id < 0) {
d0cc439b
ACM
1720 if (err == 0) {
1721 fputs("Error:\tInvalid syscall ", trace->output);
1722 err = -EINVAL;
1723 } else {
1724 fputs(", ", trace->output);
1725 }
1726
1727 fputs(sc, trace->output);
1728 }
8b3ce757
ACM
1729
1730 trace->ev_qualifier_ids.entries[i++] = id;
d0cc439b
ACM
1731 }
1732
1733 if (err < 0) {
1734 fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
1735 "\nHint:\tand: 'man syscalls'\n", trace->output);
8b3ce757
ACM
1736 zfree(&trace->ev_qualifier_ids.entries);
1737 trace->ev_qualifier_ids.nr = 0;
d0cc439b 1738 }
8b3ce757 1739out:
d0cc439b
ACM
1740 return err;
1741}
1742
55d43bca
DA
1743/*
1744 * args is to be interpreted as a series of longs but we need to handle
1745 * 8-byte unaligned accesses. args points to raw_data within the event
1746 * and raw_data is guaranteed to be 8-byte unaligned because it is
1747 * preceded by raw_size which is a u32. So we need to copy args to a temp
1748 * variable to read it. Most notably this avoids extended load instructions
1749 * on unaligned addresses
1750 */
1751
752fde44 1752static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
55d43bca 1753 unsigned char *args, struct trace *trace,
75b757ca 1754 struct thread *thread)
514f1c67 1755{
514f1c67 1756 size_t printed = 0;
55d43bca
DA
1757 unsigned char *p;
1758 unsigned long val;
514f1c67 1759
f208bd8d 1760 if (sc->args != NULL) {
514f1c67 1761 struct format_field *field;
01533e97
ACM
1762 u8 bit = 1;
1763 struct syscall_arg arg = {
75b757ca
ACM
1764 .idx = 0,
1765 .mask = 0,
1766 .trace = trace,
1767 .thread = thread,
01533e97 1768 };
6e7eeb51 1769
f208bd8d 1770 for (field = sc->args; field;
01533e97
ACM
1771 field = field->next, ++arg.idx, bit <<= 1) {
1772 if (arg.mask & bit)
6e7eeb51 1773 continue;
55d43bca
DA
1774
1775 /* special care for unaligned accesses */
1776 p = args + sizeof(unsigned long) * arg.idx;
1777 memcpy(&val, p, sizeof(val));
1778
4aa58232
ACM
1779 /*
1780 * Suppress this argument if its value is zero and
1781 * and we don't have a string associated in an
1782 * strarray for it.
1783 */
55d43bca 1784 if (val == 0 &&
4aa58232
ACM
1785 !(sc->arg_scnprintf &&
1786 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1787 sc->arg_parm[arg.idx]))
22ae5cf1
ACM
1788 continue;
1789
752fde44 1790 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 1791 "%s%s: ", printed ? ", " : "", field->name);
01533e97 1792 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
55d43bca 1793 arg.val = val;
1f115cb7
ACM
1794 if (sc->arg_parm)
1795 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
1796 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1797 size - printed, &arg);
6e7eeb51 1798 } else {
13d4ff3e 1799 printed += scnprintf(bf + printed, size - printed,
55d43bca 1800 "%ld", val);
6e7eeb51 1801 }
514f1c67
ACM
1802 }
1803 } else {
01533e97
ACM
1804 int i = 0;
1805
514f1c67 1806 while (i < 6) {
55d43bca
DA
1807 /* special care for unaligned accesses */
1808 p = args + sizeof(unsigned long) * i;
1809 memcpy(&val, p, sizeof(val));
752fde44
ACM
1810 printed += scnprintf(bf + printed, size - printed,
1811 "%sarg%d: %ld",
55d43bca 1812 printed ? ", " : "", i, val);
514f1c67
ACM
1813 ++i;
1814 }
1815 }
1816
1817 return printed;
1818}
1819
ba3d7dee 1820typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1821 union perf_event *event,
ba3d7dee
ACM
1822 struct perf_sample *sample);
1823
1824static struct syscall *trace__syscall_info(struct trace *trace,
bf2575c1 1825 struct perf_evsel *evsel, int id)
ba3d7dee 1826{
ba3d7dee
ACM
1827
1828 if (id < 0) {
adaa18bf
ACM
1829
1830 /*
1831 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1832 * before that, leaving at a higher verbosity level till that is
1833 * explained. Reproduced with plain ftrace with:
1834 *
1835 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1836 * grep "NR -1 " /t/trace_pipe
1837 *
1838 * After generating some load on the machine.
1839 */
1840 if (verbose > 1) {
1841 static u64 n;
1842 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1843 id, perf_evsel__name(evsel), ++n);
1844 }
ba3d7dee
ACM
1845 return NULL;
1846 }
1847
1848 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1849 trace__read_syscall_info(trace, id))
1850 goto out_cant_read;
1851
1852 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1853 goto out_cant_read;
1854
1855 return &trace->syscalls.table[id];
1856
1857out_cant_read:
7c304ee0
ACM
1858 if (verbose) {
1859 fprintf(trace->output, "Problems reading syscall %d", id);
1860 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1861 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1862 fputs(" information\n", trace->output);
1863 }
ba3d7dee
ACM
1864 return NULL;
1865}
1866
bf2575c1
DA
1867static void thread__update_stats(struct thread_trace *ttrace,
1868 int id, struct perf_sample *sample)
1869{
1870 struct int_node *inode;
1871 struct stats *stats;
1872 u64 duration = 0;
1873
1874 inode = intlist__findnew(ttrace->syscall_stats, id);
1875 if (inode == NULL)
1876 return;
1877
1878 stats = inode->priv;
1879 if (stats == NULL) {
1880 stats = malloc(sizeof(struct stats));
1881 if (stats == NULL)
1882 return;
1883 init_stats(stats);
1884 inode->priv = stats;
1885 }
1886
1887 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1888 duration = sample->time - ttrace->entry_time;
1889
1890 update_stats(stats, duration);
1891}
1892
e596663e
ACM
1893static int trace__printf_interrupted_entry(struct trace *trace, struct perf_sample *sample)
1894{
1895 struct thread_trace *ttrace;
1896 u64 duration;
1897 size_t printed;
1898
1899 if (trace->current == NULL)
1900 return 0;
1901
1902 ttrace = thread__priv(trace->current);
1903
1904 if (!ttrace->entry_pending)
1905 return 0;
1906
1907 duration = sample->time - ttrace->entry_time;
1908
1909 printed = trace__fprintf_entry_head(trace, trace->current, duration, sample->time, trace->output);
1910 printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str);
1911 ttrace->entry_pending = false;
1912
1913 return printed;
1914}
1915
ba3d7dee 1916static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1917 union perf_event *event __maybe_unused,
ba3d7dee
ACM
1918 struct perf_sample *sample)
1919{
752fde44 1920 char *msg;
ba3d7dee 1921 void *args;
752fde44 1922 size_t printed = 0;
2ae3a312 1923 struct thread *thread;
b91fc39f 1924 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 1925 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1926 struct thread_trace *ttrace;
1927
1928 if (sc == NULL)
1929 return -1;
ba3d7dee 1930
8fb598e5 1931 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1932 ttrace = thread__trace(thread, trace->output);
2ae3a312 1933 if (ttrace == NULL)
b91fc39f 1934 goto out_put;
ba3d7dee 1935
77170988 1936 args = perf_evsel__sc_tp_ptr(evsel, args, sample);
752fde44
ACM
1937
1938 if (ttrace->entry_str == NULL) {
e4d44e83 1939 ttrace->entry_str = malloc(trace__entry_str_size);
752fde44 1940 if (!ttrace->entry_str)
b91fc39f 1941 goto out_put;
752fde44
ACM
1942 }
1943
13f22a2d 1944 if (!trace->summary_only)
6ebad5c1 1945 trace__printf_interrupted_entry(trace, sample);
e596663e 1946
752fde44
ACM
1947 ttrace->entry_time = sample->time;
1948 msg = ttrace->entry_str;
e4d44e83 1949 printed += scnprintf(msg + printed, trace__entry_str_size - printed, "%s(", sc->name);
752fde44 1950
e4d44e83 1951 printed += syscall__scnprintf_args(sc, msg + printed, trace__entry_str_size - printed,
75b757ca 1952 args, trace, thread);
752fde44 1953
5089f20e 1954 if (sc->is_exit) {
fd2eabaf 1955 if (!trace->duration_filter && !trace->summary_only) {
c24ff998
ACM
1956 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1957 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 1958 }
752fde44
ACM
1959 } else
1960 ttrace->entry_pending = true;
ba3d7dee 1961
f3b623b8
ACM
1962 if (trace->current != thread) {
1963 thread__put(trace->current);
1964 trace->current = thread__get(thread);
1965 }
b91fc39f
ACM
1966 err = 0;
1967out_put:
1968 thread__put(thread);
1969 return err;
ba3d7dee
ACM
1970}
1971
1972static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 1973 union perf_event *event __maybe_unused,
ba3d7dee
ACM
1974 struct perf_sample *sample)
1975{
2c82c3ad 1976 long ret;
60c907ab 1977 u64 duration = 0;
2ae3a312 1978 struct thread *thread;
b91fc39f 1979 int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1;
bf2575c1 1980 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1981 struct thread_trace *ttrace;
1982
1983 if (sc == NULL)
1984 return -1;
ba3d7dee 1985
8fb598e5 1986 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1987 ttrace = thread__trace(thread, trace->output);
2ae3a312 1988 if (ttrace == NULL)
b91fc39f 1989 goto out_put;
ba3d7dee 1990
bf2575c1
DA
1991 if (trace->summary)
1992 thread__update_stats(ttrace, id, sample);
1993
77170988 1994 ret = perf_evsel__sc_tp_uint(evsel, ret, sample);
ba3d7dee 1995
c522739d
ACM
1996 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1997 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1998 trace->last_vfs_getname = NULL;
1999 ++trace->stats.vfs_getname;
2000 }
2001
752fde44
ACM
2002 ttrace->exit_time = sample->time;
2003
ae9ed035 2004 if (ttrace->entry_time) {
60c907ab 2005 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
2006 if (trace__filter_duration(trace, duration))
2007 goto out;
2008 } else if (trace->duration_filter)
2009 goto out;
60c907ab 2010
fd2eabaf
DA
2011 if (trace->summary_only)
2012 goto out;
2013
c24ff998 2014 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
2015
2016 if (ttrace->entry_pending) {
c24ff998 2017 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 2018 } else {
c24ff998
ACM
2019 fprintf(trace->output, " ... [");
2020 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
2021 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
2022 }
2023
da3c9a44
ACM
2024 if (sc->fmt == NULL) {
2025signed_print:
2c82c3ad 2026 fprintf(trace->output, ") = %ld", ret);
da3c9a44 2027 } else if (ret < 0 && sc->fmt->errmsg) {
942a91ed 2028 char bf[STRERR_BUFSIZE];
ba3d7dee
ACM
2029 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
2030 *e = audit_errno_to_name(-ret);
2031
c24ff998 2032 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 2033 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 2034 fprintf(trace->output, ") = 0 Timeout");
04b34729 2035 else if (sc->fmt->hexret)
2c82c3ad 2036 fprintf(trace->output, ") = %#lx", ret);
ba3d7dee 2037 else
da3c9a44 2038 goto signed_print;
ba3d7dee 2039
c24ff998 2040 fputc('\n', trace->output);
ae9ed035 2041out:
752fde44 2042 ttrace->entry_pending = false;
b91fc39f
ACM
2043 err = 0;
2044out_put:
2045 thread__put(thread);
2046 return err;
ba3d7dee
ACM
2047}
2048
c522739d 2049static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2050 union perf_event *event __maybe_unused,
c522739d
ACM
2051 struct perf_sample *sample)
2052{
f994592d
ACM
2053 struct thread *thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
2054 struct thread_trace *ttrace;
2055 size_t filename_len, entry_str_len, to_move;
2056 ssize_t remaining_space;
2057 char *pos;
2058 const char *filename;
2059
c522739d 2060 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
f994592d
ACM
2061
2062 if (!thread)
2063 goto out;
2064
2065 ttrace = thread__priv(thread);
2066 if (!ttrace)
2067 goto out;
2068
2069 if (!ttrace->filename.ptr)
2070 goto out;
2071
2072 entry_str_len = strlen(ttrace->entry_str);
2073 remaining_space = trace__entry_str_size - entry_str_len - 1; /* \0 */
2074 if (remaining_space <= 0)
2075 goto out;
2076
2077 filename = trace->last_vfs_getname;
2078 filename_len = strlen(filename);
2079 if (filename_len > (size_t)remaining_space) {
2080 filename += filename_len - remaining_space;
2081 filename_len = remaining_space;
2082 }
2083
2084 to_move = entry_str_len - ttrace->filename.entry_str_pos + 1; /* \0 */
2085 pos = ttrace->entry_str + ttrace->filename.entry_str_pos;
2086 memmove(pos + filename_len, pos, to_move);
2087 memcpy(pos, filename, filename_len);
2088
2089 ttrace->filename.ptr = 0;
2090 ttrace->filename.entry_str_pos = 0;
2091out:
c522739d
ACM
2092 return 0;
2093}
2094
1302d88e 2095static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
0c82adcf 2096 union perf_event *event __maybe_unused,
1302d88e
ACM
2097 struct perf_sample *sample)
2098{
2099 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
2100 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
8fb598e5 2101 struct thread *thread = machine__findnew_thread(trace->host,
314add6b
AH
2102 sample->pid,
2103 sample->tid);
c24ff998 2104 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
2105
2106 if (ttrace == NULL)
2107 goto out_dump;
2108
2109 ttrace->runtime_ms += runtime_ms;
2110 trace->runtime_ms += runtime_ms;
b91fc39f 2111 thread__put(thread);
1302d88e
ACM
2112 return 0;
2113
2114out_dump:
c24ff998 2115 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
2116 evsel->name,
2117 perf_evsel__strval(evsel, sample, "comm"),
2118 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
2119 runtime,
2120 perf_evsel__intval(evsel, sample, "vruntime"));
b91fc39f 2121 thread__put(thread);
1302d88e
ACM
2122 return 0;
2123}
2124
14a052df
ACM
2125static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
2126 union perf_event *event __maybe_unused,
2127 struct perf_sample *sample)
2128{
2129 trace__printf_interrupted_entry(trace, sample);
2130 trace__fprintf_tstamp(trace, sample->time, trace->output);
0808921a
ACM
2131
2132 if (trace->trace_syscalls)
2133 fprintf(trace->output, "( ): ");
2134
2135 fprintf(trace->output, "%s:", evsel->name);
14a052df
ACM
2136
2137 if (evsel->tp_format) {
2138 event_format__fprintf(evsel->tp_format, sample->cpu,
2139 sample->raw_data, sample->raw_size,
2140 trace->output);
2141 }
2142
2143 fprintf(trace->output, ")\n");
2144 return 0;
2145}
2146
598d02c5
SF
2147static void print_location(FILE *f, struct perf_sample *sample,
2148 struct addr_location *al,
2149 bool print_dso, bool print_sym)
2150{
2151
2152 if ((verbose || print_dso) && al->map)
2153 fprintf(f, "%s@", al->map->dso->long_name);
2154
2155 if ((verbose || print_sym) && al->sym)
4414a3c5 2156 fprintf(f, "%s+0x%" PRIx64, al->sym->name,
598d02c5
SF
2157 al->addr - al->sym->start);
2158 else if (al->map)
4414a3c5 2159 fprintf(f, "0x%" PRIx64, al->addr);
598d02c5 2160 else
4414a3c5 2161 fprintf(f, "0x%" PRIx64, sample->addr);
598d02c5
SF
2162}
2163
2164static int trace__pgfault(struct trace *trace,
2165 struct perf_evsel *evsel,
2166 union perf_event *event,
2167 struct perf_sample *sample)
2168{
2169 struct thread *thread;
2170 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
2171 struct addr_location al;
2172 char map_type = 'd';
a2ea67d7 2173 struct thread_trace *ttrace;
b91fc39f 2174 int err = -1;
598d02c5
SF
2175
2176 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
a2ea67d7
SF
2177 ttrace = thread__trace(thread, trace->output);
2178 if (ttrace == NULL)
b91fc39f 2179 goto out_put;
a2ea67d7
SF
2180
2181 if (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)
2182 ttrace->pfmaj++;
2183 else
2184 ttrace->pfmin++;
2185
2186 if (trace->summary_only)
b91fc39f 2187 goto out;
598d02c5 2188
bb871a9c 2189 thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
598d02c5
SF
2190 sample->ip, &al);
2191
2192 trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
2193
2194 fprintf(trace->output, "%sfault [",
2195 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ?
2196 "maj" : "min");
2197
2198 print_location(trace->output, sample, &al, false, true);
2199
2200 fprintf(trace->output, "] => ");
2201
bb871a9c 2202 thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
598d02c5
SF
2203 sample->addr, &al);
2204
2205 if (!al.map) {
bb871a9c 2206 thread__find_addr_location(thread, cpumode,
598d02c5
SF
2207 MAP__FUNCTION, sample->addr, &al);
2208
2209 if (al.map)
2210 map_type = 'x';
2211 else
2212 map_type = '?';
2213 }
2214
2215 print_location(trace->output, sample, &al, true, false);
2216
2217 fprintf(trace->output, " (%c%c)\n", map_type, al.level);
b91fc39f
ACM
2218out:
2219 err = 0;
2220out_put:
2221 thread__put(thread);
2222 return err;
598d02c5
SF
2223}
2224
bdc89661
DA
2225static bool skip_sample(struct trace *trace, struct perf_sample *sample)
2226{
2227 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
2228 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
2229 return false;
2230
2231 if (trace->pid_list || trace->tid_list)
2232 return true;
2233
2234 return false;
2235}
2236
6810fc91 2237static int trace__process_sample(struct perf_tool *tool,
0c82adcf 2238 union perf_event *event,
6810fc91
DA
2239 struct perf_sample *sample,
2240 struct perf_evsel *evsel,
2241 struct machine *machine __maybe_unused)
2242{
2243 struct trace *trace = container_of(tool, struct trace, tool);
2244 int err = 0;
2245
744a9719 2246 tracepoint_handler handler = evsel->handler;
6810fc91 2247
bdc89661
DA
2248 if (skip_sample(trace, sample))
2249 return 0;
2250
4bb09192 2251 if (!trace->full_time && trace->base_time == 0)
6810fc91
DA
2252 trace->base_time = sample->time;
2253
3160565f
DA
2254 if (handler) {
2255 ++trace->nr_events;
0c82adcf 2256 handler(trace, evsel, event, sample);
3160565f 2257 }
6810fc91
DA
2258
2259 return err;
2260}
2261
bdc89661
DA
2262static int parse_target_str(struct trace *trace)
2263{
2264 if (trace->opts.target.pid) {
2265 trace->pid_list = intlist__new(trace->opts.target.pid);
2266 if (trace->pid_list == NULL) {
2267 pr_err("Error parsing process id string\n");
2268 return -EINVAL;
2269 }
2270 }
2271
2272 if (trace->opts.target.tid) {
2273 trace->tid_list = intlist__new(trace->opts.target.tid);
2274 if (trace->tid_list == NULL) {
2275 pr_err("Error parsing thread id string\n");
2276 return -EINVAL;
2277 }
2278 }
2279
2280 return 0;
2281}
2282
1e28fe0a 2283static int trace__record(struct trace *trace, int argc, const char **argv)
5e2485b1
DA
2284{
2285 unsigned int rec_argc, i, j;
2286 const char **rec_argv;
2287 const char * const record_args[] = {
2288 "record",
2289 "-R",
2290 "-m", "1024",
2291 "-c", "1",
5e2485b1
DA
2292 };
2293
1e28fe0a
SF
2294 const char * const sc_args[] = { "-e", };
2295 unsigned int sc_args_nr = ARRAY_SIZE(sc_args);
2296 const char * const majpf_args[] = { "-e", "major-faults" };
2297 unsigned int majpf_args_nr = ARRAY_SIZE(majpf_args);
2298 const char * const minpf_args[] = { "-e", "minor-faults" };
2299 unsigned int minpf_args_nr = ARRAY_SIZE(minpf_args);
2300
9aca7f17 2301 /* +1 is for the event string below */
1e28fe0a
SF
2302 rec_argc = ARRAY_SIZE(record_args) + sc_args_nr + 1 +
2303 majpf_args_nr + minpf_args_nr + argc;
5e2485b1
DA
2304 rec_argv = calloc(rec_argc + 1, sizeof(char *));
2305
2306 if (rec_argv == NULL)
2307 return -ENOMEM;
2308
1e28fe0a 2309 j = 0;
5e2485b1 2310 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1e28fe0a
SF
2311 rec_argv[j++] = record_args[i];
2312
e281a960
SF
2313 if (trace->trace_syscalls) {
2314 for (i = 0; i < sc_args_nr; i++)
2315 rec_argv[j++] = sc_args[i];
2316
2317 /* event string may be different for older kernels - e.g., RHEL6 */
2318 if (is_valid_tracepoint("raw_syscalls:sys_enter"))
2319 rec_argv[j++] = "raw_syscalls:sys_enter,raw_syscalls:sys_exit";
2320 else if (is_valid_tracepoint("syscalls:sys_enter"))
2321 rec_argv[j++] = "syscalls:sys_enter,syscalls:sys_exit";
2322 else {
2323 pr_err("Neither raw_syscalls nor syscalls events exist.\n");
2324 return -1;
2325 }
9aca7f17 2326 }
9aca7f17 2327
1e28fe0a
SF
2328 if (trace->trace_pgfaults & TRACE_PFMAJ)
2329 for (i = 0; i < majpf_args_nr; i++)
2330 rec_argv[j++] = majpf_args[i];
2331
2332 if (trace->trace_pgfaults & TRACE_PFMIN)
2333 for (i = 0; i < minpf_args_nr; i++)
2334 rec_argv[j++] = minpf_args[i];
2335
2336 for (i = 0; i < (unsigned int)argc; i++)
2337 rec_argv[j++] = argv[i];
5e2485b1 2338
1e28fe0a 2339 return cmd_record(j, rec_argv, NULL);
5e2485b1
DA
2340}
2341
bf2575c1
DA
2342static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
2343
08c98776 2344static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
c522739d 2345{
ef503831 2346 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname");
c522739d 2347 if (evsel == NULL)
08c98776 2348 return false;
c522739d
ACM
2349
2350 if (perf_evsel__field(evsel, "pathname") == NULL) {
2351 perf_evsel__delete(evsel);
08c98776 2352 return false;
c522739d
ACM
2353 }
2354
744a9719 2355 evsel->handler = trace__vfs_getname;
c522739d 2356 perf_evlist__add(evlist, evsel);
08c98776 2357 return true;
c522739d
ACM
2358}
2359
598d02c5
SF
2360static int perf_evlist__add_pgfault(struct perf_evlist *evlist,
2361 u64 config)
2362{
2363 struct perf_evsel *evsel;
2364 struct perf_event_attr attr = {
2365 .type = PERF_TYPE_SOFTWARE,
2366 .mmap_data = 1,
598d02c5
SF
2367 };
2368
2369 attr.config = config;
0524798c 2370 attr.sample_period = 1;
598d02c5
SF
2371
2372 event_attr_init(&attr);
2373
2374 evsel = perf_evsel__new(&attr);
2375 if (!evsel)
2376 return -ENOMEM;
2377
2378 evsel->handler = trace__pgfault;
2379 perf_evlist__add(evlist, evsel);
2380
2381 return 0;
2382}
2383
ddbb1b13
ACM
2384static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample)
2385{
2386 const u32 type = event->header.type;
2387 struct perf_evsel *evsel;
2388
2389 if (!trace->full_time && trace->base_time == 0)
2390 trace->base_time = sample->time;
2391
2392 if (type != PERF_RECORD_SAMPLE) {
2393 trace__process_event(trace, trace->host, event, sample);
2394 return;
2395 }
2396
2397 evsel = perf_evlist__id2evsel(trace->evlist, sample->id);
2398 if (evsel == NULL) {
2399 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id);
2400 return;
2401 }
2402
2403 if (evsel->attr.type == PERF_TYPE_TRACEPOINT &&
2404 sample->raw_data == NULL) {
2405 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
2406 perf_evsel__name(evsel), sample->tid,
2407 sample->cpu, sample->raw_size);
2408 } else {
2409 tracepoint_handler handler = evsel->handler;
2410 handler(trace, evsel, event, sample);
2411 }
2412}
2413
c27366f0
ACM
2414static int trace__add_syscall_newtp(struct trace *trace)
2415{
2416 int ret = -1;
2417 struct perf_evlist *evlist = trace->evlist;
2418 struct perf_evsel *sys_enter, *sys_exit;
2419
2420 sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter);
2421 if (sys_enter == NULL)
2422 goto out;
2423
2424 if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args))
2425 goto out_delete_sys_enter;
2426
2427 sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit);
2428 if (sys_exit == NULL)
2429 goto out_delete_sys_enter;
2430
2431 if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret))
2432 goto out_delete_sys_exit;
2433
2434 perf_evlist__add(evlist, sys_enter);
2435 perf_evlist__add(evlist, sys_exit);
2436
8b3ce757
ACM
2437 trace->syscalls.events.sys_enter = sys_enter;
2438 trace->syscalls.events.sys_exit = sys_exit;
c27366f0
ACM
2439
2440 ret = 0;
2441out:
2442 return ret;
2443
2444out_delete_sys_exit:
2445 perf_evsel__delete_priv(sys_exit);
2446out_delete_sys_enter:
2447 perf_evsel__delete_priv(sys_enter);
2448 goto out;
2449}
2450
19867b61
ACM
2451static int trace__set_ev_qualifier_filter(struct trace *trace)
2452{
2453 int err = -1;
2454 char *filter = asprintf_expr_inout_ints("id", !trace->not_ev_qualifier,
2455 trace->ev_qualifier_ids.nr,
2456 trace->ev_qualifier_ids.entries);
2457
2458 if (filter == NULL)
2459 goto out_enomem;
2460
2461 if (!perf_evsel__append_filter(trace->syscalls.events.sys_enter, "&&", filter))
2462 err = perf_evsel__append_filter(trace->syscalls.events.sys_exit, "&&", filter);
2463
2464 free(filter);
2465out:
2466 return err;
2467out_enomem:
2468 errno = ENOMEM;
2469 goto out;
2470}
c27366f0 2471
f15eb531 2472static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 2473{
14a052df 2474 struct perf_evlist *evlist = trace->evlist;
94ad89bc 2475 struct perf_evsel *evsel;
efd5745e
ACM
2476 int err = -1, i;
2477 unsigned long before;
f15eb531 2478 const bool forks = argc > 0;
46fb3c21 2479 bool draining = false;
514f1c67 2480
75b757ca
ACM
2481 trace->live = true;
2482
c27366f0 2483 if (trace->trace_syscalls && trace__add_syscall_newtp(trace))
801c67b0 2484 goto out_error_raw_syscalls;
514f1c67 2485
e281a960 2486 if (trace->trace_syscalls)
08c98776 2487 trace->vfs_getname = perf_evlist__add_vfs_getname(evlist);
c522739d 2488
598d02c5 2489 if ((trace->trace_pgfaults & TRACE_PFMAJ) &&
e2726d99 2490 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) {
5ed08dae 2491 goto out_error_mem;
e2726d99 2492 }
598d02c5
SF
2493
2494 if ((trace->trace_pgfaults & TRACE_PFMIN) &&
2495 perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN))
5ed08dae 2496 goto out_error_mem;
598d02c5 2497
1302d88e 2498 if (trace->sched &&
2cc990ba
ACM
2499 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
2500 trace__sched_stat_runtime))
2501 goto out_error_sched_stat_runtime;
1302d88e 2502
514f1c67
ACM
2503 err = perf_evlist__create_maps(evlist, &trace->opts.target);
2504 if (err < 0) {
c24ff998 2505 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
2506 goto out_delete_evlist;
2507 }
2508
752fde44
ACM
2509 err = trace__symbols_init(trace, evlist);
2510 if (err < 0) {
c24ff998 2511 fprintf(trace->output, "Problems initializing symbol libraries!\n");
03ad9747 2512 goto out_delete_evlist;
752fde44
ACM
2513 }
2514
f77a9518 2515 perf_evlist__config(evlist, &trace->opts);
514f1c67 2516
f15eb531
NK
2517 signal(SIGCHLD, sig_handler);
2518 signal(SIGINT, sig_handler);
2519
2520 if (forks) {
6ef73ec4 2521 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
735f7e0b 2522 argv, false, NULL);
f15eb531 2523 if (err < 0) {
c24ff998 2524 fprintf(trace->output, "Couldn't run the workload!\n");
03ad9747 2525 goto out_delete_evlist;
f15eb531
NK
2526 }
2527 }
2528
514f1c67 2529 err = perf_evlist__open(evlist);
a8f23d8f
ACM
2530 if (err < 0)
2531 goto out_error_open;
514f1c67 2532
241b057c
ACM
2533 /*
2534 * Better not use !target__has_task() here because we need to cover the
2535 * case where no threads were specified in the command line, but a
2536 * workload was, and in that case we will fill in the thread_map when
2537 * we fork the workload in perf_evlist__prepare_workload.
2538 */
f078c385
ACM
2539 if (trace->filter_pids.nr > 0)
2540 err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
e13798c7 2541 else if (thread_map__pid(evlist->threads, 0) == -1)
f078c385
ACM
2542 err = perf_evlist__set_filter_pid(evlist, getpid());
2543
94ad89bc
ACM
2544 if (err < 0)
2545 goto out_error_mem;
2546
19867b61
ACM
2547 if (trace->ev_qualifier_ids.nr > 0) {
2548 err = trace__set_ev_qualifier_filter(trace);
2549 if (err < 0)
2550 goto out_errno;
19867b61 2551
2e5e5f87
ACM
2552 pr_debug("event qualifier tracepoint filter: %s\n",
2553 trace->syscalls.events.sys_exit->filter);
2554 }
19867b61 2555
94ad89bc
ACM
2556 err = perf_evlist__apply_filters(evlist, &evsel);
2557 if (err < 0)
2558 goto out_error_apply_filters;
241b057c 2559
f885037e 2560 err = perf_evlist__mmap(evlist, trace->opts.mmap_pages, false);
e09b18d4
ACM
2561 if (err < 0)
2562 goto out_error_mmap;
514f1c67 2563
cb24d01d
ACM
2564 if (!target__none(&trace->opts.target))
2565 perf_evlist__enable(evlist);
2566
f15eb531
NK
2567 if (forks)
2568 perf_evlist__start_workload(evlist);
2569
e13798c7 2570 trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
42052bea
ACM
2571 evlist->threads->nr > 1 ||
2572 perf_evlist__first(evlist)->attr.inherit;
514f1c67 2573again:
efd5745e 2574 before = trace->nr_events;
514f1c67
ACM
2575
2576 for (i = 0; i < evlist->nr_mmaps; i++) {
2577 union perf_event *event;
2578
2579 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
514f1c67 2580 struct perf_sample sample;
514f1c67 2581
efd5745e 2582 ++trace->nr_events;
514f1c67 2583
514f1c67
ACM
2584 err = perf_evlist__parse_sample(evlist, event, &sample);
2585 if (err) {
c24ff998 2586 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
8e50d384 2587 goto next_event;
514f1c67
ACM
2588 }
2589
ddbb1b13 2590 trace__handle_event(trace, event, &sample);
8e50d384
ZZ
2591next_event:
2592 perf_evlist__mmap_consume(evlist, i);
20c5f10e 2593
ba209f85
ACM
2594 if (interrupted)
2595 goto out_disable;
02ac5421
ACM
2596
2597 if (done && !draining) {
2598 perf_evlist__disable(evlist);
2599 draining = true;
2600 }
514f1c67
ACM
2601 }
2602 }
2603
efd5745e 2604 if (trace->nr_events == before) {
ba209f85 2605 int timeout = done ? 100 : -1;
f15eb531 2606
46fb3c21
ACM
2607 if (!draining && perf_evlist__poll(evlist, timeout) > 0) {
2608 if (perf_evlist__filter_pollfd(evlist, POLLERR | POLLHUP) == 0)
2609 draining = true;
2610
ba209f85 2611 goto again;
46fb3c21 2612 }
ba209f85
ACM
2613 } else {
2614 goto again;
f15eb531
NK
2615 }
2616
ba209f85 2617out_disable:
f3b623b8
ACM
2618 thread__zput(trace->current);
2619
ba209f85 2620 perf_evlist__disable(evlist);
514f1c67 2621
c522739d
ACM
2622 if (!err) {
2623 if (trace->summary)
2624 trace__fprintf_thread_summary(trace, trace->output);
2625
2626 if (trace->show_tool_stats) {
2627 fprintf(trace->output, "Stats:\n "
2628 " vfs_getname : %" PRIu64 "\n"
2629 " proc_getname: %" PRIu64 "\n",
2630 trace->stats.vfs_getname,
2631 trace->stats.proc_getname);
2632 }
2633 }
bf2575c1 2634
514f1c67
ACM
2635out_delete_evlist:
2636 perf_evlist__delete(evlist);
14a052df 2637 trace->evlist = NULL;
75b757ca 2638 trace->live = false;
514f1c67 2639 return err;
6ef068cb
ACM
2640{
2641 char errbuf[BUFSIZ];
a8f23d8f 2642
2cc990ba
ACM
2643out_error_sched_stat_runtime:
2644 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "sched", "sched_stat_runtime");
2645 goto out_error;
2646
801c67b0 2647out_error_raw_syscalls:
2cc990ba 2648 debugfs__strerror_open_tp(errno, errbuf, sizeof(errbuf), "raw_syscalls", "sys_(enter|exit)");
a8f23d8f
ACM
2649 goto out_error;
2650
e09b18d4
ACM
2651out_error_mmap:
2652 perf_evlist__strerror_mmap(evlist, errno, errbuf, sizeof(errbuf));
2653 goto out_error;
2654
a8f23d8f
ACM
2655out_error_open:
2656 perf_evlist__strerror_open(evlist, errno, errbuf, sizeof(errbuf));
2657
2658out_error:
6ef068cb 2659 fprintf(trace->output, "%s\n", errbuf);
87f91868 2660 goto out_delete_evlist;
94ad89bc
ACM
2661
2662out_error_apply_filters:
2663 fprintf(trace->output,
2664 "Failed to set filter \"%s\" on event %s with %d (%s)\n",
2665 evsel->filter, perf_evsel__name(evsel), errno,
2666 strerror_r(errno, errbuf, sizeof(errbuf)));
2667 goto out_delete_evlist;
514f1c67 2668}
5ed08dae
ACM
2669out_error_mem:
2670 fprintf(trace->output, "Not enough memory to run!\n");
2671 goto out_delete_evlist;
19867b61
ACM
2672
2673out_errno:
2674 fprintf(trace->output, "errno=%d,%s\n", errno, strerror(errno));
2675 goto out_delete_evlist;
a8f23d8f 2676}
514f1c67 2677
6810fc91
DA
2678static int trace__replay(struct trace *trace)
2679{
2680 const struct perf_evsel_str_handler handlers[] = {
c522739d 2681 { "probe:vfs_getname", trace__vfs_getname, },
6810fc91 2682 };
f5fc1412
JO
2683 struct perf_data_file file = {
2684 .path = input_name,
2685 .mode = PERF_DATA_MODE_READ,
e366a6d8 2686 .force = trace->force,
f5fc1412 2687 };
6810fc91 2688 struct perf_session *session;
003824e8 2689 struct perf_evsel *evsel;
6810fc91
DA
2690 int err = -1;
2691
2692 trace->tool.sample = trace__process_sample;
2693 trace->tool.mmap = perf_event__process_mmap;
384c671e 2694 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
2695 trace->tool.comm = perf_event__process_comm;
2696 trace->tool.exit = perf_event__process_exit;
2697 trace->tool.fork = perf_event__process_fork;
2698 trace->tool.attr = perf_event__process_attr;
2699 trace->tool.tracing_data = perf_event__process_tracing_data;
2700 trace->tool.build_id = perf_event__process_build_id;
2701
0a8cb85c 2702 trace->tool.ordered_events = true;
6810fc91
DA
2703 trace->tool.ordering_requires_timestamps = true;
2704
2705 /* add tid to output */
2706 trace->multiple_threads = true;
2707
f5fc1412 2708 session = perf_session__new(&file, false, &trace->tool);
6810fc91 2709 if (session == NULL)
52e02834 2710 return -1;
6810fc91 2711
0a7e6d1b 2712 if (symbol__init(&session->header.env) < 0)
cb2ffae2
NK
2713 goto out;
2714
8fb598e5
DA
2715 trace->host = &session->machines.host;
2716
6810fc91
DA
2717 err = perf_session__set_tracepoints_handlers(session, handlers);
2718 if (err)
2719 goto out;
2720
003824e8
NK
2721 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2722 "raw_syscalls:sys_enter");
9aca7f17
DA
2723 /* older kernels have syscalls tp versus raw_syscalls */
2724 if (evsel == NULL)
2725 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2726 "syscalls:sys_enter");
003824e8 2727
e281a960
SF
2728 if (evsel &&
2729 (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 ||
2730 perf_evsel__init_sc_tp_ptr_field(evsel, args))) {
003824e8
NK
2731 pr_err("Error during initialize raw_syscalls:sys_enter event\n");
2732 goto out;
2733 }
2734
2735 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2736 "raw_syscalls:sys_exit");
9aca7f17
DA
2737 if (evsel == NULL)
2738 evsel = perf_evlist__find_tracepoint_by_name(session->evlist,
2739 "syscalls:sys_exit");
e281a960
SF
2740 if (evsel &&
2741 (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 ||
2742 perf_evsel__init_sc_tp_uint_field(evsel, ret))) {
003824e8 2743 pr_err("Error during initialize raw_syscalls:sys_exit event\n");
6810fc91
DA
2744 goto out;
2745 }
2746
1e28fe0a
SF
2747 evlist__for_each(session->evlist, evsel) {
2748 if (evsel->attr.type == PERF_TYPE_SOFTWARE &&
2749 (evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ||
2750 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MIN ||
2751 evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS))
2752 evsel->handler = trace__pgfault;
2753 }
2754
bdc89661
DA
2755 err = parse_target_str(trace);
2756 if (err != 0)
2757 goto out;
2758
6810fc91
DA
2759 setup_pager();
2760
b7b61cbe 2761 err = perf_session__process_events(session);
6810fc91
DA
2762 if (err)
2763 pr_err("Failed to process events, error %d", err);
2764
bf2575c1
DA
2765 else if (trace->summary)
2766 trace__fprintf_thread_summary(trace, trace->output);
2767
6810fc91
DA
2768out:
2769 perf_session__delete(session);
2770
2771 return err;
2772}
2773
1302d88e
ACM
2774static size_t trace__fprintf_threads_header(FILE *fp)
2775{
2776 size_t printed;
2777
99ff7150 2778 printed = fprintf(fp, "\n Summary of events:\n\n");
bf2575c1
DA
2779
2780 return printed;
2781}
2782
2783static size_t thread__dump_stats(struct thread_trace *ttrace,
2784 struct trace *trace, FILE *fp)
2785{
2786 struct stats *stats;
2787 size_t printed = 0;
2788 struct syscall *sc;
2789 struct int_node *inode = intlist__first(ttrace->syscall_stats);
2790
2791 if (inode == NULL)
2792 return 0;
2793
2794 printed += fprintf(fp, "\n");
2795
834fd46d
MW
2796 printed += fprintf(fp, " syscall calls total min avg max stddev\n");
2797 printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n");
2798 printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n");
99ff7150 2799
bf2575c1
DA
2800 /* each int_node is a syscall */
2801 while (inode) {
2802 stats = inode->priv;
2803 if (stats) {
2804 double min = (double)(stats->min) / NSEC_PER_MSEC;
2805 double max = (double)(stats->max) / NSEC_PER_MSEC;
2806 double avg = avg_stats(stats);
2807 double pct;
2808 u64 n = (u64) stats->n;
2809
2810 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
2811 avg /= NSEC_PER_MSEC;
2812
2813 sc = &trace->syscalls.table[inode->i];
99ff7150 2814 printed += fprintf(fp, " %-15s", sc->name);
834fd46d
MW
2815 printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f",
2816 n, avg * n, min, avg);
27a778b5 2817 printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct);
bf2575c1
DA
2818 }
2819
2820 inode = intlist__next(inode);
2821 }
2822
2823 printed += fprintf(fp, "\n\n");
1302d88e
ACM
2824
2825 return printed;
2826}
2827
896cbb56
DA
2828/* struct used to pass data to per-thread function */
2829struct summary_data {
2830 FILE *fp;
2831 struct trace *trace;
2832 size_t printed;
2833};
2834
2835static int trace__fprintf_one_thread(struct thread *thread, void *priv)
2836{
2837 struct summary_data *data = priv;
2838 FILE *fp = data->fp;
2839 size_t printed = data->printed;
2840 struct trace *trace = data->trace;
89dceb22 2841 struct thread_trace *ttrace = thread__priv(thread);
896cbb56
DA
2842 double ratio;
2843
2844 if (ttrace == NULL)
2845 return 0;
2846
2847 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
2848
15e65c69 2849 printed += fprintf(fp, " %s (%d), ", thread__comm_str(thread), thread->tid);
99ff7150 2850 printed += fprintf(fp, "%lu events, ", ttrace->nr_events);
15e65c69 2851 printed += fprintf(fp, "%.1f%%", ratio);
a2ea67d7
SF
2852 if (ttrace->pfmaj)
2853 printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj);
2854 if (ttrace->pfmin)
2855 printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin);
99ff7150 2856 printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms);
bf2575c1 2857 printed += thread__dump_stats(ttrace, trace, fp);
896cbb56
DA
2858
2859 data->printed += printed;
2860
2861 return 0;
2862}
2863
1302d88e
ACM
2864static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2865{
896cbb56
DA
2866 struct summary_data data = {
2867 .fp = fp,
2868 .trace = trace
2869 };
2870 data.printed = trace__fprintf_threads_header(fp);
1302d88e 2871
896cbb56
DA
2872 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
2873
2874 return data.printed;
1302d88e
ACM
2875}
2876
ae9ed035
ACM
2877static int trace__set_duration(const struct option *opt, const char *str,
2878 int unset __maybe_unused)
2879{
2880 struct trace *trace = opt->value;
2881
2882 trace->duration_filter = atof(str);
2883 return 0;
2884}
2885
f078c385
ACM
2886static int trace__set_filter_pids(const struct option *opt, const char *str,
2887 int unset __maybe_unused)
2888{
2889 int ret = -1;
2890 size_t i;
2891 struct trace *trace = opt->value;
2892 /*
2893 * FIXME: introduce a intarray class, plain parse csv and create a
2894 * { int nr, int entries[] } struct...
2895 */
2896 struct intlist *list = intlist__new(str);
2897
2898 if (list == NULL)
2899 return -1;
2900
2901 i = trace->filter_pids.nr = intlist__nr_entries(list) + 1;
2902 trace->filter_pids.entries = calloc(i, sizeof(pid_t));
2903
2904 if (trace->filter_pids.entries == NULL)
2905 goto out;
2906
2907 trace->filter_pids.entries[0] = getpid();
2908
2909 for (i = 1; i < trace->filter_pids.nr; ++i)
2910 trace->filter_pids.entries[i] = intlist__entry(list, i - 1)->i;
2911
2912 intlist__delete(list);
2913 ret = 0;
2914out:
2915 return ret;
2916}
2917
c24ff998
ACM
2918static int trace__open_output(struct trace *trace, const char *filename)
2919{
2920 struct stat st;
2921
2922 if (!stat(filename, &st) && st.st_size) {
2923 char oldname[PATH_MAX];
2924
2925 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2926 unlink(oldname);
2927 rename(filename, oldname);
2928 }
2929
2930 trace->output = fopen(filename, "w");
2931
2932 return trace->output == NULL ? -errno : 0;
2933}
2934
598d02c5
SF
2935static int parse_pagefaults(const struct option *opt, const char *str,
2936 int unset __maybe_unused)
2937{
2938 int *trace_pgfaults = opt->value;
2939
2940 if (strcmp(str, "all") == 0)
2941 *trace_pgfaults |= TRACE_PFMAJ | TRACE_PFMIN;
2942 else if (strcmp(str, "maj") == 0)
2943 *trace_pgfaults |= TRACE_PFMAJ;
2944 else if (strcmp(str, "min") == 0)
2945 *trace_pgfaults |= TRACE_PFMIN;
2946 else
2947 return -1;
2948
2949 return 0;
2950}
2951
14a052df
ACM
2952static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler)
2953{
2954 struct perf_evsel *evsel;
2955
2956 evlist__for_each(evlist, evsel)
2957 evsel->handler = handler;
2958}
2959
514f1c67
ACM
2960int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2961{
6fdd9cb7 2962 const char *trace_usage[] = {
f15eb531
NK
2963 "perf trace [<options>] [<command>]",
2964 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
2965 "perf trace record [<options>] [<command>]",
2966 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
2967 NULL
2968 };
2969 struct trace trace = {
c522739d
ACM
2970 .audit = {
2971 .machine = audit_detect_machine(),
2972 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2973 },
514f1c67
ACM
2974 .syscalls = {
2975 . max = -1,
2976 },
2977 .opts = {
2978 .target = {
2979 .uid = UINT_MAX,
2980 .uses_mmap = true,
2981 },
2982 .user_freq = UINT_MAX,
2983 .user_interval = ULLONG_MAX,
509051ea 2984 .no_buffering = true,
38d5447d 2985 .mmap_pages = UINT_MAX,
9d9cad76 2986 .proc_map_timeout = 500,
514f1c67 2987 },
007d66a0 2988 .output = stderr,
50c95cbd 2989 .show_comm = true,
e281a960 2990 .trace_syscalls = true,
514f1c67 2991 };
c24ff998 2992 const char *output_name = NULL;
2ae3a312 2993 const char *ev_qualifier_str = NULL;
514f1c67 2994 const struct option trace_options[] = {
14a052df
ACM
2995 OPT_CALLBACK(0, "event", &trace.evlist, "event",
2996 "event selector. use 'perf list' to list available events",
2997 parse_events_option),
50c95cbd
ACM
2998 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2999 "show the thread COMM next to its id"),
c522739d 3000 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
d303e85a 3001 OPT_STRING('e', "expr", &ev_qualifier_str, "expr", "list of syscalls to trace"),
c24ff998 3002 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 3003 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
3004 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
3005 "trace events on existing process id"),
ac9be8ee 3006 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 3007 "trace events on existing thread id"),
fa0e4ffe
ACM
3008 OPT_CALLBACK(0, "filter-pids", &trace, "CSV list of pids",
3009 "pids to filter (by the kernel)", trace__set_filter_pids),
ac9be8ee 3010 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 3011 "system-wide collection from all CPUs"),
ac9be8ee 3012 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 3013 "list of cpus to monitor"),
6810fc91 3014 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 3015 "child tasks do not inherit counters"),
994a1f78
JO
3016 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
3017 "number of mmap data pages",
3018 perf_evlist__parse_mmap_pages),
ac9be8ee 3019 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 3020 "user to profile"),
ae9ed035
ACM
3021 OPT_CALLBACK(0, "duration", &trace, "float",
3022 "show only events with duration > N.M ms",
3023 trace__set_duration),
1302d88e 3024 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 3025 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
3026 OPT_BOOLEAN('T', "time", &trace.full_time,
3027 "Show full timestamp, not time relative to first start"),
fd2eabaf
DA
3028 OPT_BOOLEAN('s', "summary", &trace.summary_only,
3029 "Show only syscall summary with statistics"),
3030 OPT_BOOLEAN('S', "with-summary", &trace.summary,
3031 "Show all syscalls and summary with statistics"),
598d02c5
SF
3032 OPT_CALLBACK_DEFAULT('F', "pf", &trace.trace_pgfaults, "all|maj|min",
3033 "Trace pagefaults", parse_pagefaults, "maj"),
e281a960 3034 OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"),
e366a6d8 3035 OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"),
9d9cad76
KL
3036 OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout,
3037 "per thread proc mmap processing timeout in ms"),
514f1c67
ACM
3038 OPT_END()
3039 };
6fdd9cb7 3040 const char * const trace_subcommands[] = { "record", NULL };
514f1c67 3041 int err;
32caf0d1 3042 char bf[BUFSIZ];
514f1c67 3043
4d08cb80
ACM
3044 signal(SIGSEGV, sighandler_dump_stack);
3045 signal(SIGFPE, sighandler_dump_stack);
3046
14a052df 3047 trace.evlist = perf_evlist__new();
14a052df
ACM
3048
3049 if (trace.evlist == NULL) {
3050 pr_err("Not enough memory to run!\n");
ff8f695c 3051 err = -ENOMEM;
14a052df
ACM
3052 goto out;
3053 }
3054
6fdd9cb7
YS
3055 argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands,
3056 trace_usage, PARSE_OPT_STOP_AT_NON_OPTION);
fd2eabaf 3057
598d02c5
SF
3058 if (trace.trace_pgfaults) {
3059 trace.opts.sample_address = true;
3060 trace.opts.sample_time = true;
3061 }
3062
14a052df
ACM
3063 if (trace.evlist->nr_entries > 0)
3064 evlist__set_evsel_handler(trace.evlist, trace__event_handler);
3065
1e28fe0a
SF
3066 if ((argc >= 1) && (strcmp(argv[0], "record") == 0))
3067 return trace__record(&trace, argc-1, &argv[1]);
3068
3069 /* summary_only implies summary option, but don't overwrite summary if set */
3070 if (trace.summary_only)
3071 trace.summary = trace.summary_only;
3072
726f3234
ACM
3073 if (!trace.trace_syscalls && !trace.trace_pgfaults &&
3074 trace.evlist->nr_entries == 0 /* Was --events used? */) {
e281a960
SF
3075 pr_err("Please specify something to trace.\n");
3076 return -1;
3077 }
3078
c24ff998
ACM
3079 if (output_name != NULL) {
3080 err = trace__open_output(&trace, output_name);
3081 if (err < 0) {
3082 perror("failed to create output file");
3083 goto out;
3084 }
3085 }
3086
2ae3a312 3087 if (ev_qualifier_str != NULL) {
b059efdf 3088 const char *s = ev_qualifier_str;
005438a8
ACM
3089 struct strlist_config slist_config = {
3090 .dirname = system_path(STRACE_GROUPS_DIR),
3091 };
b059efdf
ACM
3092
3093 trace.not_ev_qualifier = *s == '!';
3094 if (trace.not_ev_qualifier)
3095 ++s;
005438a8 3096 trace.ev_qualifier = strlist__new(s, &slist_config);
2ae3a312 3097 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
3098 fputs("Not enough memory to parse event qualifier",
3099 trace.output);
3100 err = -ENOMEM;
3101 goto out_close;
2ae3a312 3102 }
d0cc439b
ACM
3103
3104 err = trace__validate_ev_qualifier(&trace);
3105 if (err)
3106 goto out_close;
2ae3a312
ACM
3107 }
3108
602ad878 3109 err = target__validate(&trace.opts.target);
32caf0d1 3110 if (err) {
602ad878 3111 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
3112 fprintf(trace.output, "%s", bf);
3113 goto out_close;
32caf0d1
NK
3114 }
3115
602ad878 3116 err = target__parse_uid(&trace.opts.target);
514f1c67 3117 if (err) {
602ad878 3118 target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
3119 fprintf(trace.output, "%s", bf);
3120 goto out_close;
514f1c67
ACM
3121 }
3122
602ad878 3123 if (!argc && target__none(&trace.opts.target))
ee76120e
NK
3124 trace.opts.target.system_wide = true;
3125
6810fc91
DA
3126 if (input_name)
3127 err = trace__replay(&trace);
3128 else
3129 err = trace__run(&trace, argc, argv);
1302d88e 3130
c24ff998
ACM
3131out_close:
3132 if (output_name != NULL)
3133 fclose(trace.output);
3134out:
1302d88e 3135 return err;
514f1c67 3136}
This page took 0.318013 seconds and 5 git commands to generate.