perf trace: Use vfs_getname hook if available
[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"
752fde44 6#include "util/machine.h"
6810fc91 7#include "util/session.h"
752fde44 8#include "util/thread.h"
514f1c67 9#include "util/parse-options.h"
2ae3a312 10#include "util/strlist.h"
bdc89661 11#include "util/intlist.h"
514f1c67 12#include "util/thread_map.h"
bf2575c1 13#include "util/stat.h"
514f1c67
ACM
14
15#include <libaudit.h>
16#include <stdlib.h>
49af9e93 17#include <sys/eventfd.h>
ae685380 18#include <sys/mman.h>
f9da0b0c 19#include <linux/futex.h>
514f1c67 20
456857bd
IM
21/* For older distros: */
22#ifndef MAP_STACK
23# define MAP_STACK 0x20000
24#endif
25
26#ifndef MADV_HWPOISON
27# define MADV_HWPOISON 100
28#endif
29
30#ifndef MADV_MERGEABLE
31# define MADV_MERGEABLE 12
32#endif
33
34#ifndef MADV_UNMERGEABLE
35# define MADV_UNMERGEABLE 13
36#endif
37
01533e97
ACM
38struct syscall_arg {
39 unsigned long val;
75b757ca
ACM
40 struct thread *thread;
41 struct trace *trace;
1f115cb7 42 void *parm;
01533e97
ACM
43 u8 idx;
44 u8 mask;
45};
46
1f115cb7 47struct strarray {
03e3adc9 48 int offset;
1f115cb7
ACM
49 int nr_entries;
50 const char **entries;
51};
52
53#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
54 .nr_entries = ARRAY_SIZE(array), \
55 .entries = array, \
56}
57
03e3adc9
ACM
58#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
59 .offset = off, \
60 .nr_entries = ARRAY_SIZE(array), \
61 .entries = array, \
62}
63
975b7c2f
ACM
64static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
65 const char *intfmt,
66 struct syscall_arg *arg)
1f115cb7 67{
1f115cb7 68 struct strarray *sa = arg->parm;
03e3adc9 69 int idx = arg->val - sa->offset;
1f115cb7
ACM
70
71 if (idx < 0 || idx >= sa->nr_entries)
975b7c2f 72 return scnprintf(bf, size, intfmt, arg->val);
1f115cb7
ACM
73
74 return scnprintf(bf, size, "%s", sa->entries[idx]);
75}
76
975b7c2f
ACM
77static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
78 struct syscall_arg *arg)
79{
80 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
81}
82
1f115cb7
ACM
83#define SCA_STRARRAY syscall_arg__scnprintf_strarray
84
78645cf3
ACM
85static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
86 struct syscall_arg *arg)
87{
88 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
89}
90
91#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
92
75b757ca
ACM
93static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
94 struct syscall_arg *arg);
95
96#define SCA_FD syscall_arg__scnprintf_fd
97
98static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
99 struct syscall_arg *arg)
100{
101 int fd = arg->val;
102
103 if (fd == AT_FDCWD)
104 return scnprintf(bf, size, "CWD");
105
106 return syscall_arg__scnprintf_fd(bf, size, arg);
107}
108
109#define SCA_FDAT syscall_arg__scnprintf_fd_at
110
111static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
112 struct syscall_arg *arg);
113
114#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
115
6e7eeb51 116static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
01533e97 117 struct syscall_arg *arg)
13d4ff3e 118{
01533e97 119 return scnprintf(bf, size, "%#lx", arg->val);
13d4ff3e
ACM
120}
121
beccb2b5
ACM
122#define SCA_HEX syscall_arg__scnprintf_hex
123
6e7eeb51 124static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
01533e97 125 struct syscall_arg *arg)
ae685380 126{
01533e97 127 int printed = 0, prot = arg->val;
ae685380
ACM
128
129 if (prot == PROT_NONE)
130 return scnprintf(bf, size, "NONE");
131#define P_MMAP_PROT(n) \
132 if (prot & PROT_##n) { \
133 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
134 prot &= ~PROT_##n; \
135 }
136
137 P_MMAP_PROT(EXEC);
138 P_MMAP_PROT(READ);
139 P_MMAP_PROT(WRITE);
140#ifdef PROT_SEM
141 P_MMAP_PROT(SEM);
142#endif
143 P_MMAP_PROT(GROWSDOWN);
144 P_MMAP_PROT(GROWSUP);
145#undef P_MMAP_PROT
146
147 if (prot)
148 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
149
150 return printed;
151}
152
153#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
154
6e7eeb51 155static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
01533e97 156 struct syscall_arg *arg)
941557e0 157{
01533e97 158 int printed = 0, flags = arg->val;
941557e0
ACM
159
160#define P_MMAP_FLAG(n) \
161 if (flags & MAP_##n) { \
162 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
163 flags &= ~MAP_##n; \
164 }
165
166 P_MMAP_FLAG(SHARED);
167 P_MMAP_FLAG(PRIVATE);
41817815 168#ifdef MAP_32BIT
941557e0 169 P_MMAP_FLAG(32BIT);
41817815 170#endif
941557e0
ACM
171 P_MMAP_FLAG(ANONYMOUS);
172 P_MMAP_FLAG(DENYWRITE);
173 P_MMAP_FLAG(EXECUTABLE);
174 P_MMAP_FLAG(FILE);
175 P_MMAP_FLAG(FIXED);
176 P_MMAP_FLAG(GROWSDOWN);
f2935f3e 177#ifdef MAP_HUGETLB
941557e0 178 P_MMAP_FLAG(HUGETLB);
f2935f3e 179#endif
941557e0
ACM
180 P_MMAP_FLAG(LOCKED);
181 P_MMAP_FLAG(NONBLOCK);
182 P_MMAP_FLAG(NORESERVE);
183 P_MMAP_FLAG(POPULATE);
184 P_MMAP_FLAG(STACK);
185#ifdef MAP_UNINITIALIZED
186 P_MMAP_FLAG(UNINITIALIZED);
187#endif
188#undef P_MMAP_FLAG
189
190 if (flags)
191 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
192
193 return printed;
194}
195
196#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
197
6e7eeb51 198static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
01533e97 199 struct syscall_arg *arg)
9e9716d1 200{
01533e97 201 int behavior = arg->val;
9e9716d1
ACM
202
203 switch (behavior) {
204#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
205 P_MADV_BHV(NORMAL);
206 P_MADV_BHV(RANDOM);
207 P_MADV_BHV(SEQUENTIAL);
208 P_MADV_BHV(WILLNEED);
209 P_MADV_BHV(DONTNEED);
210 P_MADV_BHV(REMOVE);
211 P_MADV_BHV(DONTFORK);
212 P_MADV_BHV(DOFORK);
213 P_MADV_BHV(HWPOISON);
214#ifdef MADV_SOFT_OFFLINE
215 P_MADV_BHV(SOFT_OFFLINE);
216#endif
217 P_MADV_BHV(MERGEABLE);
218 P_MADV_BHV(UNMERGEABLE);
f2935f3e 219#ifdef MADV_HUGEPAGE
9e9716d1 220 P_MADV_BHV(HUGEPAGE);
f2935f3e
DA
221#endif
222#ifdef MADV_NOHUGEPAGE
9e9716d1 223 P_MADV_BHV(NOHUGEPAGE);
f2935f3e 224#endif
9e9716d1
ACM
225#ifdef MADV_DONTDUMP
226 P_MADV_BHV(DONTDUMP);
227#endif
228#ifdef MADV_DODUMP
229 P_MADV_BHV(DODUMP);
230#endif
231#undef P_MADV_PHV
232 default: break;
233 }
234
235 return scnprintf(bf, size, "%#x", behavior);
236}
237
238#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
239
5cea6ff2
ACM
240static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
241 struct syscall_arg *arg)
242{
243 int printed = 0, op = arg->val;
244
245 if (op == 0)
246 return scnprintf(bf, size, "NONE");
247#define P_CMD(cmd) \
248 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
249 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
250 op &= ~LOCK_##cmd; \
251 }
252
253 P_CMD(SH);
254 P_CMD(EX);
255 P_CMD(NB);
256 P_CMD(UN);
257 P_CMD(MAND);
258 P_CMD(RW);
259 P_CMD(READ);
260 P_CMD(WRITE);
261#undef P_OP
262
263 if (op)
264 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
265
266 return printed;
267}
268
269#define SCA_FLOCK syscall_arg__scnprintf_flock
270
01533e97 271static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
f9da0b0c
ACM
272{
273 enum syscall_futex_args {
274 SCF_UADDR = (1 << 0),
275 SCF_OP = (1 << 1),
276 SCF_VAL = (1 << 2),
277 SCF_TIMEOUT = (1 << 3),
278 SCF_UADDR2 = (1 << 4),
279 SCF_VAL3 = (1 << 5),
280 };
01533e97 281 int op = arg->val;
f9da0b0c
ACM
282 int cmd = op & FUTEX_CMD_MASK;
283 size_t printed = 0;
284
285 switch (cmd) {
286#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
01533e97
ACM
287 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
288 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
289 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
290 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
291 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
292 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
f9da0b0c 293 P_FUTEX_OP(WAKE_OP); break;
01533e97
ACM
294 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
295 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
296 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
297 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
298 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
f9da0b0c
ACM
299 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
300 default: printed = scnprintf(bf, size, "%#x", cmd); break;
301 }
302
303 if (op & FUTEX_PRIVATE_FLAG)
304 printed += scnprintf(bf + printed, size - printed, "|PRIV");
305
306 if (op & FUTEX_CLOCK_REALTIME)
307 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
308
309 return printed;
310}
311
efe6b882
ACM
312#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
313
03e3adc9
ACM
314static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
315static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
eac032c5 316
1f115cb7
ACM
317static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
318static DEFINE_STRARRAY(itimers);
319
efe6b882
ACM
320static const char *whences[] = { "SET", "CUR", "END",
321#ifdef SEEK_DATA
322"DATA",
323#endif
324#ifdef SEEK_HOLE
325"HOLE",
326#endif
327};
328static DEFINE_STRARRAY(whences);
f9da0b0c 329
80f587d5
ACM
330static const char *fcntl_cmds[] = {
331 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
332 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
333 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
334 "F_GETOWNER_UIDS",
335};
336static DEFINE_STRARRAY(fcntl_cmds);
337
c045bf02
ACM
338static const char *rlimit_resources[] = {
339 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
340 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
341 "RTTIME",
342};
343static DEFINE_STRARRAY(rlimit_resources);
344
eb5b1b14
ACM
345static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
346static DEFINE_STRARRAY(sighow);
347
4f8c1b74
DA
348static const char *clockid[] = {
349 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
350 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
351};
352static DEFINE_STRARRAY(clockid);
353
e10bce81
ACM
354static const char *socket_families[] = {
355 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
356 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
357 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
358 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
359 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
360 "ALG", "NFC", "VSOCK",
361};
362static DEFINE_STRARRAY(socket_families);
363
a28b24b2
ACM
364#ifndef SOCK_TYPE_MASK
365#define SOCK_TYPE_MASK 0xf
366#endif
367
368static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
369 struct syscall_arg *arg)
370{
371 size_t printed;
372 int type = arg->val,
373 flags = type & ~SOCK_TYPE_MASK;
374
375 type &= SOCK_TYPE_MASK;
376 /*
377 * Can't use a strarray, MIPS may override for ABI reasons.
378 */
379 switch (type) {
380#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
381 P_SK_TYPE(STREAM);
382 P_SK_TYPE(DGRAM);
383 P_SK_TYPE(RAW);
384 P_SK_TYPE(RDM);
385 P_SK_TYPE(SEQPACKET);
386 P_SK_TYPE(DCCP);
387 P_SK_TYPE(PACKET);
388#undef P_SK_TYPE
389 default:
390 printed = scnprintf(bf, size, "%#x", type);
391 }
392
393#define P_SK_FLAG(n) \
394 if (flags & SOCK_##n) { \
395 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
396 flags &= ~SOCK_##n; \
397 }
398
399 P_SK_FLAG(CLOEXEC);
400 P_SK_FLAG(NONBLOCK);
401#undef P_SK_FLAG
402
403 if (flags)
404 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
405
406 return printed;
407}
408
409#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
410
b2cc99fd
ACM
411#ifndef MSG_PROBE
412#define MSG_PROBE 0x10
413#endif
b6e8f8f4
DA
414#ifndef MSG_WAITFORONE
415#define MSG_WAITFORONE 0x10000
416#endif
b2cc99fd
ACM
417#ifndef MSG_SENDPAGE_NOTLAST
418#define MSG_SENDPAGE_NOTLAST 0x20000
419#endif
420#ifndef MSG_FASTOPEN
421#define MSG_FASTOPEN 0x20000000
422#endif
423
424static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
425 struct syscall_arg *arg)
426{
427 int printed = 0, flags = arg->val;
428
429 if (flags == 0)
430 return scnprintf(bf, size, "NONE");
431#define P_MSG_FLAG(n) \
432 if (flags & MSG_##n) { \
433 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
434 flags &= ~MSG_##n; \
435 }
436
437 P_MSG_FLAG(OOB);
438 P_MSG_FLAG(PEEK);
439 P_MSG_FLAG(DONTROUTE);
440 P_MSG_FLAG(TRYHARD);
441 P_MSG_FLAG(CTRUNC);
442 P_MSG_FLAG(PROBE);
443 P_MSG_FLAG(TRUNC);
444 P_MSG_FLAG(DONTWAIT);
445 P_MSG_FLAG(EOR);
446 P_MSG_FLAG(WAITALL);
447 P_MSG_FLAG(FIN);
448 P_MSG_FLAG(SYN);
449 P_MSG_FLAG(CONFIRM);
450 P_MSG_FLAG(RST);
451 P_MSG_FLAG(ERRQUEUE);
452 P_MSG_FLAG(NOSIGNAL);
453 P_MSG_FLAG(MORE);
454 P_MSG_FLAG(WAITFORONE);
455 P_MSG_FLAG(SENDPAGE_NOTLAST);
456 P_MSG_FLAG(FASTOPEN);
457 P_MSG_FLAG(CMSG_CLOEXEC);
458#undef P_MSG_FLAG
459
460 if (flags)
461 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
462
463 return printed;
464}
465
466#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
467
51108999
ACM
468static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
469 struct syscall_arg *arg)
470{
471 size_t printed = 0;
472 int mode = arg->val;
473
474 if (mode == F_OK) /* 0 */
475 return scnprintf(bf, size, "F");
476#define P_MODE(n) \
477 if (mode & n##_OK) { \
478 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
479 mode &= ~n##_OK; \
480 }
481
482 P_MODE(R);
483 P_MODE(W);
484 P_MODE(X);
485#undef P_MODE
486
487 if (mode)
488 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
489
490 return printed;
491}
492
493#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
494
be65a89a 495static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
01533e97 496 struct syscall_arg *arg)
be65a89a 497{
01533e97 498 int printed = 0, flags = arg->val;
be65a89a
ACM
499
500 if (!(flags & O_CREAT))
01533e97 501 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
be65a89a
ACM
502
503 if (flags == 0)
504 return scnprintf(bf, size, "RDONLY");
505#define P_FLAG(n) \
506 if (flags & O_##n) { \
507 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
508 flags &= ~O_##n; \
509 }
510
511 P_FLAG(APPEND);
512 P_FLAG(ASYNC);
513 P_FLAG(CLOEXEC);
514 P_FLAG(CREAT);
515 P_FLAG(DIRECT);
516 P_FLAG(DIRECTORY);
517 P_FLAG(EXCL);
518 P_FLAG(LARGEFILE);
519 P_FLAG(NOATIME);
520 P_FLAG(NOCTTY);
521#ifdef O_NONBLOCK
522 P_FLAG(NONBLOCK);
523#elif O_NDELAY
524 P_FLAG(NDELAY);
525#endif
526#ifdef O_PATH
527 P_FLAG(PATH);
528#endif
529 P_FLAG(RDWR);
530#ifdef O_DSYNC
531 if ((flags & O_SYNC) == O_SYNC)
532 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
533 else {
534 P_FLAG(DSYNC);
535 }
536#else
537 P_FLAG(SYNC);
538#endif
539 P_FLAG(TRUNC);
540 P_FLAG(WRONLY);
541#undef P_FLAG
542
543 if (flags)
544 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
545
546 return printed;
547}
548
549#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
550
49af9e93
ACM
551static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
552 struct syscall_arg *arg)
553{
554 int printed = 0, flags = arg->val;
555
556 if (flags == 0)
557 return scnprintf(bf, size, "NONE");
558#define P_FLAG(n) \
559 if (flags & EFD_##n) { \
560 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
561 flags &= ~EFD_##n; \
562 }
563
564 P_FLAG(SEMAPHORE);
565 P_FLAG(CLOEXEC);
566 P_FLAG(NONBLOCK);
567#undef P_FLAG
568
569 if (flags)
570 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
571
572 return printed;
573}
574
575#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
576
46cce19b
ACM
577static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
578 struct syscall_arg *arg)
579{
580 int printed = 0, flags = arg->val;
581
582#define P_FLAG(n) \
583 if (flags & O_##n) { \
584 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
585 flags &= ~O_##n; \
586 }
587
588 P_FLAG(CLOEXEC);
589 P_FLAG(NONBLOCK);
590#undef P_FLAG
591
592 if (flags)
593 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
594
595 return printed;
596}
597
598#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
599
8bad5b0a
ACM
600static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
601{
602 int sig = arg->val;
603
604 switch (sig) {
605#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
606 P_SIGNUM(HUP);
607 P_SIGNUM(INT);
608 P_SIGNUM(QUIT);
609 P_SIGNUM(ILL);
610 P_SIGNUM(TRAP);
611 P_SIGNUM(ABRT);
612 P_SIGNUM(BUS);
613 P_SIGNUM(FPE);
614 P_SIGNUM(KILL);
615 P_SIGNUM(USR1);
616 P_SIGNUM(SEGV);
617 P_SIGNUM(USR2);
618 P_SIGNUM(PIPE);
619 P_SIGNUM(ALRM);
620 P_SIGNUM(TERM);
621 P_SIGNUM(STKFLT);
622 P_SIGNUM(CHLD);
623 P_SIGNUM(CONT);
624 P_SIGNUM(STOP);
625 P_SIGNUM(TSTP);
626 P_SIGNUM(TTIN);
627 P_SIGNUM(TTOU);
628 P_SIGNUM(URG);
629 P_SIGNUM(XCPU);
630 P_SIGNUM(XFSZ);
631 P_SIGNUM(VTALRM);
632 P_SIGNUM(PROF);
633 P_SIGNUM(WINCH);
634 P_SIGNUM(IO);
635 P_SIGNUM(PWR);
636 P_SIGNUM(SYS);
637 default: break;
638 }
639
640 return scnprintf(bf, size, "%#x", sig);
641}
642
643#define SCA_SIGNUM syscall_arg__scnprintf_signum
644
78645cf3
ACM
645#define TCGETS 0x5401
646
647static const char *tioctls[] = {
648 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
649 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
650 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
651 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
652 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
653 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
654 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
655 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
656 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
657 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
658 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
659 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
660 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
661 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
662 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
663};
664
665static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
666
453350dd
ACM
667#define STRARRAY(arg, name, array) \
668 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
669 .arg_parm = { [arg] = &strarray__##array, }
670
514f1c67
ACM
671static struct syscall_fmt {
672 const char *name;
aec1930b 673 const char *alias;
01533e97 674 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 675 void *arg_parm[6];
514f1c67
ACM
676 bool errmsg;
677 bool timeout;
04b34729 678 bool hexret;
514f1c67 679} syscall_fmts[] = {
51108999
ACM
680 { .name = "access", .errmsg = true,
681 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
aec1930b 682 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
beccb2b5
ACM
683 { .name = "brk", .hexret = true,
684 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
4f8c1b74 685 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
75b757ca
ACM
686 { .name = "close", .errmsg = true,
687 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
a14bb860 688 { .name = "connect", .errmsg = true, },
75b757ca
ACM
689 { .name = "dup", .errmsg = true,
690 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
691 { .name = "dup2", .errmsg = true,
692 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
693 { .name = "dup3", .errmsg = true,
694 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 695 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
49af9e93
ACM
696 { .name = "eventfd2", .errmsg = true,
697 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
75b757ca
ACM
698 { .name = "faccessat", .errmsg = true,
699 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
700 { .name = "fadvise64", .errmsg = true,
701 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
702 { .name = "fallocate", .errmsg = true,
703 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
704 { .name = "fchdir", .errmsg = true,
705 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
706 { .name = "fchmod", .errmsg = true,
707 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
708 { .name = "fchmodat", .errmsg = true,
709 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
710 { .name = "fchown", .errmsg = true,
711 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
712 { .name = "fchownat", .errmsg = true,
713 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
714 { .name = "fcntl", .errmsg = true,
715 .arg_scnprintf = { [0] = SCA_FD, /* fd */
716 [1] = SCA_STRARRAY, /* cmd */ },
717 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
718 { .name = "fdatasync", .errmsg = true,
719 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
5cea6ff2 720 { .name = "flock", .errmsg = true,
75b757ca
ACM
721 .arg_scnprintf = { [0] = SCA_FD, /* fd */
722 [1] = SCA_FLOCK, /* cmd */ }, },
723 { .name = "fsetxattr", .errmsg = true,
724 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
725 { .name = "fstat", .errmsg = true, .alias = "newfstat",
726 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
727 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
728 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
729 { .name = "fstatfs", .errmsg = true,
730 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
731 { .name = "fsync", .errmsg = true,
732 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
733 { .name = "ftruncate", .errmsg = true,
734 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
f9da0b0c
ACM
735 { .name = "futex", .errmsg = true,
736 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
75b757ca
ACM
737 { .name = "futimesat", .errmsg = true,
738 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
739 { .name = "getdents", .errmsg = true,
740 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
741 { .name = "getdents64", .errmsg = true,
742 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd
ACM
743 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
744 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
beccb2b5 745 { .name = "ioctl", .errmsg = true,
75b757ca 746 .arg_scnprintf = { [0] = SCA_FD, /* fd */
78645cf3
ACM
747 [1] = SCA_STRHEXARRAY, /* cmd */
748 [2] = SCA_HEX, /* arg */ },
749 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
8bad5b0a
ACM
750 { .name = "kill", .errmsg = true,
751 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
75b757ca
ACM
752 { .name = "linkat", .errmsg = true,
753 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
754 { .name = "lseek", .errmsg = true,
755 .arg_scnprintf = { [0] = SCA_FD, /* fd */
756 [2] = SCA_STRARRAY, /* whence */ },
757 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
e5959683 758 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
9e9716d1
ACM
759 { .name = "madvise", .errmsg = true,
760 .arg_scnprintf = { [0] = SCA_HEX, /* start */
761 [2] = SCA_MADV_BHV, /* behavior */ }, },
75b757ca
ACM
762 { .name = "mkdirat", .errmsg = true,
763 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
764 { .name = "mknodat", .errmsg = true,
765 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
3d903aa7
ACM
766 { .name = "mlock", .errmsg = true,
767 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
768 { .name = "mlockall", .errmsg = true,
769 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5 770 { .name = "mmap", .hexret = true,
ae685380 771 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
941557e0
ACM
772 [2] = SCA_MMAP_PROT, /* prot */
773 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
beccb2b5 774 { .name = "mprotect", .errmsg = true,
ae685380
ACM
775 .arg_scnprintf = { [0] = SCA_HEX, /* start */
776 [2] = SCA_MMAP_PROT, /* prot */ }, },
777 { .name = "mremap", .hexret = true,
778 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
779 [4] = SCA_HEX, /* new_addr */ }, },
3d903aa7
ACM
780 { .name = "munlock", .errmsg = true,
781 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
beccb2b5
ACM
782 { .name = "munmap", .errmsg = true,
783 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
75b757ca
ACM
784 { .name = "name_to_handle_at", .errmsg = true,
785 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
786 { .name = "newfstatat", .errmsg = true,
787 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
be65a89a
ACM
788 { .name = "open", .errmsg = true,
789 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 790 { .name = "open_by_handle_at", .errmsg = true,
75b757ca
ACM
791 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
792 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
31cd3855 793 { .name = "openat", .errmsg = true,
75b757ca
ACM
794 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
795 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
46cce19b
ACM
796 { .name = "pipe2", .errmsg = true,
797 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
aec1930b
ACM
798 { .name = "poll", .errmsg = true, .timeout = true, },
799 { .name = "ppoll", .errmsg = true, .timeout = true, },
75b757ca
ACM
800 { .name = "pread", .errmsg = true, .alias = "pread64",
801 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
802 { .name = "preadv", .errmsg = true, .alias = "pread",
803 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
453350dd 804 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
75b757ca
ACM
805 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
806 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
807 { .name = "pwritev", .errmsg = true,
808 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
809 { .name = "read", .errmsg = true,
810 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
811 { .name = "readlinkat", .errmsg = true,
812 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
813 { .name = "readv", .errmsg = true,
814 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
b2cc99fd
ACM
815 { .name = "recvfrom", .errmsg = true,
816 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
817 { .name = "recvmmsg", .errmsg = true,
818 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
819 { .name = "recvmsg", .errmsg = true,
820 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
75b757ca
ACM
821 { .name = "renameat", .errmsg = true,
822 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
823 { .name = "rt_sigaction", .errmsg = true,
824 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
453350dd 825 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
8bad5b0a
ACM
826 { .name = "rt_sigqueueinfo", .errmsg = true,
827 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
828 { .name = "rt_tgsigqueueinfo", .errmsg = true,
829 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
aec1930b 830 { .name = "select", .errmsg = true, .timeout = true, },
b2cc99fd
ACM
831 { .name = "sendmmsg", .errmsg = true,
832 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
833 { .name = "sendmsg", .errmsg = true,
834 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
835 { .name = "sendto", .errmsg = true,
836 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
453350dd
ACM
837 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
838 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
75b757ca
ACM
839 { .name = "shutdown", .errmsg = true,
840 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
e10bce81 841 { .name = "socket", .errmsg = true,
a28b24b2
ACM
842 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
843 [1] = SCA_SK_TYPE, /* type */ },
07120aa5
ACM
844 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
845 { .name = "socketpair", .errmsg = true,
846 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
847 [1] = SCA_SK_TYPE, /* type */ },
e10bce81 848 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
aec1930b 849 { .name = "stat", .errmsg = true, .alias = "newstat", },
75b757ca
ACM
850 { .name = "symlinkat", .errmsg = true,
851 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
8bad5b0a
ACM
852 { .name = "tgkill", .errmsg = true,
853 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
854 { .name = "tkill", .errmsg = true,
855 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
e5959683 856 { .name = "uname", .errmsg = true, .alias = "newuname", },
75b757ca
ACM
857 { .name = "unlinkat", .errmsg = true,
858 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
859 { .name = "utimensat", .errmsg = true,
860 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
861 { .name = "write", .errmsg = true,
862 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
863 { .name = "writev", .errmsg = true,
864 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
514f1c67
ACM
865};
866
867static int syscall_fmt__cmp(const void *name, const void *fmtp)
868{
869 const struct syscall_fmt *fmt = fmtp;
870 return strcmp(name, fmt->name);
871}
872
873static struct syscall_fmt *syscall_fmt__find(const char *name)
874{
875 const int nmemb = ARRAY_SIZE(syscall_fmts);
876 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
877}
878
879struct syscall {
880 struct event_format *tp_format;
881 const char *name;
2ae3a312 882 bool filtered;
514f1c67 883 struct syscall_fmt *fmt;
01533e97 884 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
1f115cb7 885 void **arg_parm;
514f1c67
ACM
886};
887
60c907ab
ACM
888static size_t fprintf_duration(unsigned long t, FILE *fp)
889{
890 double duration = (double)t / NSEC_PER_MSEC;
891 size_t printed = fprintf(fp, "(");
892
893 if (duration >= 1.0)
894 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
895 else if (duration >= 0.01)
896 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
897 else
898 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
c24ff998 899 return printed + fprintf(fp, "): ");
60c907ab
ACM
900}
901
752fde44
ACM
902struct thread_trace {
903 u64 entry_time;
904 u64 exit_time;
905 bool entry_pending;
efd5745e 906 unsigned long nr_events;
752fde44 907 char *entry_str;
1302d88e 908 double runtime_ms;
75b757ca
ACM
909 struct {
910 int max;
911 char **table;
912 } paths;
bf2575c1
DA
913
914 struct intlist *syscall_stats;
752fde44
ACM
915};
916
917static struct thread_trace *thread_trace__new(void)
918{
75b757ca
ACM
919 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
920
921 if (ttrace)
922 ttrace->paths.max = -1;
923
bf2575c1
DA
924 ttrace->syscall_stats = intlist__new(NULL);
925
75b757ca 926 return ttrace;
752fde44
ACM
927}
928
c24ff998 929static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
752fde44 930{
efd5745e
ACM
931 struct thread_trace *ttrace;
932
752fde44
ACM
933 if (thread == NULL)
934 goto fail;
935
936 if (thread->priv == NULL)
937 thread->priv = thread_trace__new();
efd5745e 938
752fde44
ACM
939 if (thread->priv == NULL)
940 goto fail;
941
efd5745e
ACM
942 ttrace = thread->priv;
943 ++ttrace->nr_events;
944
945 return ttrace;
752fde44 946fail:
c24ff998 947 color_fprintf(fp, PERF_COLOR_RED,
752fde44
ACM
948 "WARNING: not enough memory, dropping samples!\n");
949 return NULL;
950}
951
514f1c67 952struct trace {
c24ff998 953 struct perf_tool tool;
c522739d
ACM
954 struct {
955 int machine;
956 int open_id;
957 } audit;
514f1c67
ACM
958 struct {
959 int max;
960 struct syscall *table;
961 } syscalls;
962 struct perf_record_opts opts;
8fb598e5 963 struct machine *host;
752fde44 964 u64 base_time;
4bb09192 965 bool full_time;
c24ff998 966 FILE *output;
efd5745e 967 unsigned long nr_events;
b059efdf
ACM
968 struct strlist *ev_qualifier;
969 bool not_ev_qualifier;
75b757ca 970 bool live;
c522739d 971 const char *last_vfs_getname;
bdc89661
DA
972 struct intlist *tid_list;
973 struct intlist *pid_list;
1302d88e 974 bool sched;
752fde44 975 bool multiple_threads;
bf2575c1 976 bool summary;
50c95cbd 977 bool show_comm;
c522739d 978 bool show_tool_stats;
ae9ed035 979 double duration_filter;
1302d88e 980 double runtime_ms;
c522739d
ACM
981 struct {
982 u64 vfs_getname, proc_getname;
983 } stats;
514f1c67
ACM
984};
985
97119f37 986static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname)
75b757ca
ACM
987{
988 struct thread_trace *ttrace = thread->priv;
75b757ca
ACM
989
990 if (fd > ttrace->paths.max) {
991 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
992
993 if (npath == NULL)
994 return -1;
995
996 if (ttrace->paths.max != -1) {
997 memset(npath + ttrace->paths.max + 1, 0,
998 (fd - ttrace->paths.max) * sizeof(char *));
999 } else {
1000 memset(npath, 0, (fd + 1) * sizeof(char *));
1001 }
1002
1003 ttrace->paths.table = npath;
1004 ttrace->paths.max = fd;
1005 }
1006
1007 ttrace->paths.table[fd] = strdup(pathname);
1008
1009 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1010}
1011
97119f37
ACM
1012static int thread__read_fd_path(struct thread *thread, int fd)
1013{
1014 char linkname[PATH_MAX], pathname[PATH_MAX];
1015 struct stat st;
1016 int ret;
1017
1018 if (thread->pid_ == thread->tid) {
1019 scnprintf(linkname, sizeof(linkname),
1020 "/proc/%d/fd/%d", thread->pid_, fd);
1021 } else {
1022 scnprintf(linkname, sizeof(linkname),
1023 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
1024 }
1025
1026 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
1027 return -1;
1028
1029 ret = readlink(linkname, pathname, sizeof(pathname));
1030
1031 if (ret < 0 || ret > st.st_size)
1032 return -1;
1033
1034 pathname[ret] = '\0';
1035 return trace__set_fd_pathname(thread, fd, pathname);
1036}
1037
c522739d
ACM
1038static const char *thread__fd_path(struct thread *thread, int fd,
1039 struct trace *trace)
75b757ca
ACM
1040{
1041 struct thread_trace *ttrace = thread->priv;
1042
1043 if (ttrace == NULL)
1044 return NULL;
1045
1046 if (fd < 0)
1047 return NULL;
1048
c522739d
ACM
1049 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL))
1050 if (!trace->live)
1051 return NULL;
1052 ++trace->stats.proc_getname;
1053 if (thread__read_fd_path(thread, fd)) {
1054 return NULL;
1055 }
75b757ca
ACM
1056
1057 return ttrace->paths.table[fd];
1058}
1059
1060static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1061 struct syscall_arg *arg)
1062{
1063 int fd = arg->val;
1064 size_t printed = scnprintf(bf, size, "%d", fd);
c522739d 1065 const char *path = thread__fd_path(arg->thread, fd, arg->trace);
75b757ca
ACM
1066
1067 if (path)
1068 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1069
1070 return printed;
1071}
1072
1073static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1074 struct syscall_arg *arg)
1075{
1076 int fd = arg->val;
1077 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1078 struct thread_trace *ttrace = arg->thread->priv;
1079
1080 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1081 free(ttrace->paths.table[fd]);
1082 ttrace->paths.table[fd] = NULL;
1083 }
1084
1085 return printed;
1086}
1087
ae9ed035
ACM
1088static bool trace__filter_duration(struct trace *trace, double t)
1089{
1090 return t < (trace->duration_filter * NSEC_PER_MSEC);
1091}
1092
752fde44
ACM
1093static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1094{
1095 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1096
60c907ab 1097 return fprintf(fp, "%10.3f ", ts);
752fde44
ACM
1098}
1099
f15eb531
NK
1100static bool done = false;
1101
1102static void sig_handler(int sig __maybe_unused)
1103{
1104 done = true;
1105}
1106
752fde44 1107static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
60c907ab 1108 u64 duration, u64 tstamp, FILE *fp)
752fde44
ACM
1109{
1110 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
60c907ab 1111 printed += fprintf_duration(duration, fp);
752fde44 1112
50c95cbd
ACM
1113 if (trace->multiple_threads) {
1114 if (trace->show_comm)
1115 printed += fprintf(fp, "%.14s/", thread->comm);
38051234 1116 printed += fprintf(fp, "%d ", thread->tid);
50c95cbd 1117 }
752fde44
ACM
1118
1119 return printed;
1120}
1121
c24ff998
ACM
1122static int trace__process_event(struct trace *trace, struct machine *machine,
1123 union perf_event *event)
752fde44
ACM
1124{
1125 int ret = 0;
1126
1127 switch (event->header.type) {
1128 case PERF_RECORD_LOST:
c24ff998 1129 color_fprintf(trace->output, PERF_COLOR_RED,
752fde44
ACM
1130 "LOST %" PRIu64 " events!\n", event->lost.lost);
1131 ret = machine__process_lost_event(machine, event);
1132 default:
1133 ret = machine__process_event(machine, event);
1134 break;
1135 }
1136
1137 return ret;
1138}
1139
c24ff998 1140static int trace__tool_process(struct perf_tool *tool,
752fde44
ACM
1141 union perf_event *event,
1142 struct perf_sample *sample __maybe_unused,
1143 struct machine *machine)
1144{
c24ff998
ACM
1145 struct trace *trace = container_of(tool, struct trace, tool);
1146 return trace__process_event(trace, machine, event);
752fde44
ACM
1147}
1148
1149static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1150{
1151 int err = symbol__init();
1152
1153 if (err)
1154 return err;
1155
8fb598e5
DA
1156 trace->host = machine__new_host();
1157 if (trace->host == NULL)
1158 return -ENOMEM;
752fde44
ACM
1159
1160 if (perf_target__has_task(&trace->opts.target)) {
c24ff998 1161 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
752fde44 1162 trace__tool_process,
8fb598e5 1163 trace->host);
752fde44 1164 } else {
c24ff998 1165 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
8fb598e5 1166 trace->host);
752fde44
ACM
1167 }
1168
1169 if (err)
1170 symbol__exit();
1171
1172 return err;
1173}
1174
13d4ff3e
ACM
1175static int syscall__set_arg_fmts(struct syscall *sc)
1176{
1177 struct format_field *field;
1178 int idx = 0;
1179
1180 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1181 if (sc->arg_scnprintf == NULL)
1182 return -1;
1183
1f115cb7
ACM
1184 if (sc->fmt)
1185 sc->arg_parm = sc->fmt->arg_parm;
1186
13d4ff3e 1187 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
beccb2b5
ACM
1188 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1189 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1190 else if (field->flags & FIELD_IS_POINTER)
13d4ff3e
ACM
1191 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1192 ++idx;
1193 }
1194
1195 return 0;
1196}
1197
514f1c67
ACM
1198static int trace__read_syscall_info(struct trace *trace, int id)
1199{
1200 char tp_name[128];
1201 struct syscall *sc;
c522739d 1202 const char *name = audit_syscall_to_name(id, trace->audit.machine);
3a531260
ACM
1203
1204 if (name == NULL)
1205 return -1;
514f1c67
ACM
1206
1207 if (id > trace->syscalls.max) {
1208 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1209
1210 if (nsyscalls == NULL)
1211 return -1;
1212
1213 if (trace->syscalls.max != -1) {
1214 memset(nsyscalls + trace->syscalls.max + 1, 0,
1215 (id - trace->syscalls.max) * sizeof(*sc));
1216 } else {
1217 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1218 }
1219
1220 trace->syscalls.table = nsyscalls;
1221 trace->syscalls.max = id;
1222 }
1223
1224 sc = trace->syscalls.table + id;
3a531260 1225 sc->name = name;
2ae3a312 1226
b059efdf
ACM
1227 if (trace->ev_qualifier) {
1228 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1229
1230 if (!(in ^ trace->not_ev_qualifier)) {
1231 sc->filtered = true;
1232 /*
1233 * No need to do read tracepoint information since this will be
1234 * filtered out.
1235 */
1236 return 0;
1237 }
2ae3a312
ACM
1238 }
1239
3a531260 1240 sc->fmt = syscall_fmt__find(sc->name);
514f1c67 1241
aec1930b 1242 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
514f1c67 1243 sc->tp_format = event_format__new("syscalls", tp_name);
aec1930b
ACM
1244
1245 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1246 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1247 sc->tp_format = event_format__new("syscalls", tp_name);
1248 }
514f1c67 1249
13d4ff3e
ACM
1250 if (sc->tp_format == NULL)
1251 return -1;
1252
1253 return syscall__set_arg_fmts(sc);
514f1c67
ACM
1254}
1255
752fde44 1256static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
75b757ca
ACM
1257 unsigned long *args, struct trace *trace,
1258 struct thread *thread)
514f1c67 1259{
514f1c67
ACM
1260 size_t printed = 0;
1261
1262 if (sc->tp_format != NULL) {
1263 struct format_field *field;
01533e97
ACM
1264 u8 bit = 1;
1265 struct syscall_arg arg = {
75b757ca
ACM
1266 .idx = 0,
1267 .mask = 0,
1268 .trace = trace,
1269 .thread = thread,
01533e97 1270 };
6e7eeb51
ACM
1271
1272 for (field = sc->tp_format->format.fields->next; field;
01533e97
ACM
1273 field = field->next, ++arg.idx, bit <<= 1) {
1274 if (arg.mask & bit)
6e7eeb51 1275 continue;
4aa58232
ACM
1276 /*
1277 * Suppress this argument if its value is zero and
1278 * and we don't have a string associated in an
1279 * strarray for it.
1280 */
1281 if (args[arg.idx] == 0 &&
1282 !(sc->arg_scnprintf &&
1283 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1284 sc->arg_parm[arg.idx]))
22ae5cf1
ACM
1285 continue;
1286
752fde44 1287 printed += scnprintf(bf + printed, size - printed,
13d4ff3e 1288 "%s%s: ", printed ? ", " : "", field->name);
01533e97
ACM
1289 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1290 arg.val = args[arg.idx];
1f115cb7
ACM
1291 if (sc->arg_parm)
1292 arg.parm = sc->arg_parm[arg.idx];
01533e97
ACM
1293 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1294 size - printed, &arg);
6e7eeb51 1295 } else {
13d4ff3e 1296 printed += scnprintf(bf + printed, size - printed,
01533e97 1297 "%ld", args[arg.idx]);
6e7eeb51 1298 }
514f1c67
ACM
1299 }
1300 } else {
01533e97
ACM
1301 int i = 0;
1302
514f1c67 1303 while (i < 6) {
752fde44
ACM
1304 printed += scnprintf(bf + printed, size - printed,
1305 "%sarg%d: %ld",
1306 printed ? ", " : "", i, args[i]);
514f1c67
ACM
1307 ++i;
1308 }
1309 }
1310
1311 return printed;
1312}
1313
ba3d7dee
ACM
1314typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1315 struct perf_sample *sample);
1316
1317static struct syscall *trace__syscall_info(struct trace *trace,
bf2575c1 1318 struct perf_evsel *evsel, int id)
ba3d7dee 1319{
ba3d7dee
ACM
1320
1321 if (id < 0) {
adaa18bf
ACM
1322
1323 /*
1324 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1325 * before that, leaving at a higher verbosity level till that is
1326 * explained. Reproduced with plain ftrace with:
1327 *
1328 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1329 * grep "NR -1 " /t/trace_pipe
1330 *
1331 * After generating some load on the machine.
1332 */
1333 if (verbose > 1) {
1334 static u64 n;
1335 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1336 id, perf_evsel__name(evsel), ++n);
1337 }
ba3d7dee
ACM
1338 return NULL;
1339 }
1340
1341 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1342 trace__read_syscall_info(trace, id))
1343 goto out_cant_read;
1344
1345 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1346 goto out_cant_read;
1347
1348 return &trace->syscalls.table[id];
1349
1350out_cant_read:
7c304ee0
ACM
1351 if (verbose) {
1352 fprintf(trace->output, "Problems reading syscall %d", id);
1353 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1354 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1355 fputs(" information\n", trace->output);
1356 }
ba3d7dee
ACM
1357 return NULL;
1358}
1359
bf2575c1
DA
1360static void thread__update_stats(struct thread_trace *ttrace,
1361 int id, struct perf_sample *sample)
1362{
1363 struct int_node *inode;
1364 struct stats *stats;
1365 u64 duration = 0;
1366
1367 inode = intlist__findnew(ttrace->syscall_stats, id);
1368 if (inode == NULL)
1369 return;
1370
1371 stats = inode->priv;
1372 if (stats == NULL) {
1373 stats = malloc(sizeof(struct stats));
1374 if (stats == NULL)
1375 return;
1376 init_stats(stats);
1377 inode->priv = stats;
1378 }
1379
1380 if (ttrace->entry_time && sample->time > ttrace->entry_time)
1381 duration = sample->time - ttrace->entry_time;
1382
1383 update_stats(stats, duration);
1384}
1385
ba3d7dee
ACM
1386static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1387 struct perf_sample *sample)
1388{
752fde44 1389 char *msg;
ba3d7dee 1390 void *args;
752fde44 1391 size_t printed = 0;
2ae3a312 1392 struct thread *thread;
bf2575c1
DA
1393 int id = perf_evsel__intval(evsel, sample, "id");
1394 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1395 struct thread_trace *ttrace;
1396
1397 if (sc == NULL)
1398 return -1;
ba3d7dee 1399
2ae3a312
ACM
1400 if (sc->filtered)
1401 return 0;
1402
8fb598e5 1403 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1404 ttrace = thread__trace(thread, trace->output);
2ae3a312 1405 if (ttrace == NULL)
ba3d7dee
ACM
1406 return -1;
1407
1408 args = perf_evsel__rawptr(evsel, sample, "args");
1409 if (args == NULL) {
c24ff998 1410 fprintf(trace->output, "Problems reading syscall arguments\n");
ba3d7dee
ACM
1411 return -1;
1412 }
1413
752fde44
ACM
1414 ttrace = thread->priv;
1415
1416 if (ttrace->entry_str == NULL) {
1417 ttrace->entry_str = malloc(1024);
1418 if (!ttrace->entry_str)
1419 return -1;
1420 }
1421
1422 ttrace->entry_time = sample->time;
1423 msg = ttrace->entry_str;
1424 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1425
75b757ca
ACM
1426 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1427 args, trace, thread);
752fde44
ACM
1428
1429 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
ae9ed035 1430 if (!trace->duration_filter) {
c24ff998
ACM
1431 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1432 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
ae9ed035 1433 }
752fde44
ACM
1434 } else
1435 ttrace->entry_pending = true;
ba3d7dee
ACM
1436
1437 return 0;
1438}
1439
1440static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1441 struct perf_sample *sample)
1442{
1443 int ret;
60c907ab 1444 u64 duration = 0;
2ae3a312 1445 struct thread *thread;
bf2575c1
DA
1446 int id = perf_evsel__intval(evsel, sample, "id");
1447 struct syscall *sc = trace__syscall_info(trace, evsel, id);
2ae3a312
ACM
1448 struct thread_trace *ttrace;
1449
1450 if (sc == NULL)
1451 return -1;
ba3d7dee 1452
2ae3a312
ACM
1453 if (sc->filtered)
1454 return 0;
1455
8fb598e5 1456 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
c24ff998 1457 ttrace = thread__trace(thread, trace->output);
2ae3a312 1458 if (ttrace == NULL)
ba3d7dee
ACM
1459 return -1;
1460
bf2575c1
DA
1461 if (trace->summary)
1462 thread__update_stats(ttrace, id, sample);
1463
ba3d7dee
ACM
1464 ret = perf_evsel__intval(evsel, sample, "ret");
1465
c522739d
ACM
1466 if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) {
1467 trace__set_fd_pathname(thread, ret, trace->last_vfs_getname);
1468 trace->last_vfs_getname = NULL;
1469 ++trace->stats.vfs_getname;
1470 }
1471
752fde44
ACM
1472 ttrace = thread->priv;
1473
1474 ttrace->exit_time = sample->time;
1475
ae9ed035 1476 if (ttrace->entry_time) {
60c907ab 1477 duration = sample->time - ttrace->entry_time;
ae9ed035
ACM
1478 if (trace__filter_duration(trace, duration))
1479 goto out;
1480 } else if (trace->duration_filter)
1481 goto out;
60c907ab 1482
c24ff998 1483 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
752fde44
ACM
1484
1485 if (ttrace->entry_pending) {
c24ff998 1486 fprintf(trace->output, "%-70s", ttrace->entry_str);
752fde44 1487 } else {
c24ff998
ACM
1488 fprintf(trace->output, " ... [");
1489 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1490 fprintf(trace->output, "]: %s()", sc->name);
752fde44
ACM
1491 }
1492
da3c9a44
ACM
1493 if (sc->fmt == NULL) {
1494signed_print:
1495 fprintf(trace->output, ") = %d", ret);
1496 } else if (ret < 0 && sc->fmt->errmsg) {
ba3d7dee
ACM
1497 char bf[256];
1498 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1499 *e = audit_errno_to_name(-ret);
1500
c24ff998 1501 fprintf(trace->output, ") = -1 %s %s", e, emsg);
da3c9a44 1502 } else if (ret == 0 && sc->fmt->timeout)
c24ff998 1503 fprintf(trace->output, ") = 0 Timeout");
04b34729
ACM
1504 else if (sc->fmt->hexret)
1505 fprintf(trace->output, ") = %#x", ret);
ba3d7dee 1506 else
da3c9a44 1507 goto signed_print;
ba3d7dee 1508
c24ff998 1509 fputc('\n', trace->output);
ae9ed035 1510out:
752fde44
ACM
1511 ttrace->entry_pending = false;
1512
ba3d7dee
ACM
1513 return 0;
1514}
1515
c522739d
ACM
1516static int trace__vfs_getname(struct trace *trace, struct perf_evsel *evsel,
1517 struct perf_sample *sample)
1518{
1519 trace->last_vfs_getname = perf_evsel__rawptr(evsel, sample, "pathname");
1520 return 0;
1521}
1522
1302d88e
ACM
1523static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1524 struct perf_sample *sample)
1525{
1526 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1527 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
8fb598e5 1528 struct thread *thread = machine__findnew_thread(trace->host,
314add6b
AH
1529 sample->pid,
1530 sample->tid);
c24ff998 1531 struct thread_trace *ttrace = thread__trace(thread, trace->output);
1302d88e
ACM
1532
1533 if (ttrace == NULL)
1534 goto out_dump;
1535
1536 ttrace->runtime_ms += runtime_ms;
1537 trace->runtime_ms += runtime_ms;
1538 return 0;
1539
1540out_dump:
c24ff998 1541 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
1302d88e
ACM
1542 evsel->name,
1543 perf_evsel__strval(evsel, sample, "comm"),
1544 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1545 runtime,
1546 perf_evsel__intval(evsel, sample, "vruntime"));
1547 return 0;
1548}
1549
bdc89661
DA
1550static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1551{
1552 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1553 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1554 return false;
1555
1556 if (trace->pid_list || trace->tid_list)
1557 return true;
1558
1559 return false;
1560}
1561
6810fc91
DA
1562static int trace__process_sample(struct perf_tool *tool,
1563 union perf_event *event __maybe_unused,
1564 struct perf_sample *sample,
1565 struct perf_evsel *evsel,
1566 struct machine *machine __maybe_unused)
1567{
1568 struct trace *trace = container_of(tool, struct trace, tool);
1569 int err = 0;
1570
1571 tracepoint_handler handler = evsel->handler.func;
1572
bdc89661
DA
1573 if (skip_sample(trace, sample))
1574 return 0;
1575
4bb09192 1576 if (!trace->full_time && trace->base_time == 0)
6810fc91
DA
1577 trace->base_time = sample->time;
1578
1579 if (handler)
1580 handler(trace, evsel, sample);
1581
1582 return err;
1583}
1584
1585static bool
1586perf_session__has_tp(struct perf_session *session, const char *name)
1587{
1588 struct perf_evsel *evsel;
1589
1590 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1591
1592 return evsel != NULL;
1593}
1594
bdc89661
DA
1595static int parse_target_str(struct trace *trace)
1596{
1597 if (trace->opts.target.pid) {
1598 trace->pid_list = intlist__new(trace->opts.target.pid);
1599 if (trace->pid_list == NULL) {
1600 pr_err("Error parsing process id string\n");
1601 return -EINVAL;
1602 }
1603 }
1604
1605 if (trace->opts.target.tid) {
1606 trace->tid_list = intlist__new(trace->opts.target.tid);
1607 if (trace->tid_list == NULL) {
1608 pr_err("Error parsing thread id string\n");
1609 return -EINVAL;
1610 }
1611 }
1612
1613 return 0;
1614}
1615
5e2485b1
DA
1616static int trace__record(int argc, const char **argv)
1617{
1618 unsigned int rec_argc, i, j;
1619 const char **rec_argv;
1620 const char * const record_args[] = {
1621 "record",
1622 "-R",
1623 "-m", "1024",
1624 "-c", "1",
1625 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1626 };
1627
1628 rec_argc = ARRAY_SIZE(record_args) + argc;
1629 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1630
1631 if (rec_argv == NULL)
1632 return -ENOMEM;
1633
1634 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1635 rec_argv[i] = record_args[i];
1636
1637 for (j = 0; j < (unsigned int)argc; j++, i++)
1638 rec_argv[i] = argv[j];
1639
1640 return cmd_record(i, rec_argv, NULL);
1641}
1642
bf2575c1
DA
1643static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
1644
c522739d
ACM
1645static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist)
1646{
1647 struct perf_evsel *evsel = perf_evsel__newtp("probe", "vfs_getname",
1648 evlist->nr_entries);
1649 if (evsel == NULL)
1650 return;
1651
1652 if (perf_evsel__field(evsel, "pathname") == NULL) {
1653 perf_evsel__delete(evsel);
1654 return;
1655 }
1656
1657 evsel->handler.func = trace__vfs_getname;
1658 perf_evlist__add(evlist, evsel);
1659}
1660
f15eb531 1661static int trace__run(struct trace *trace, int argc, const char **argv)
514f1c67 1662{
334fe7a3 1663 struct perf_evlist *evlist = perf_evlist__new();
ba3d7dee 1664 struct perf_evsel *evsel;
efd5745e
ACM
1665 int err = -1, i;
1666 unsigned long before;
f15eb531 1667 const bool forks = argc > 0;
514f1c67 1668
75b757ca
ACM
1669 trace->live = true;
1670
514f1c67 1671 if (evlist == NULL) {
c24ff998 1672 fprintf(trace->output, "Not enough memory to run!\n");
514f1c67
ACM
1673 goto out;
1674 }
1675
39876e7d 1676 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
87f91868
RR
1677 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit))
1678 goto out_error_tp;
514f1c67 1679
c522739d
ACM
1680 perf_evlist__add_vfs_getname(evlist);
1681
1302d88e 1682 if (trace->sched &&
87f91868
RR
1683 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1684 trace__sched_stat_runtime))
1685 goto out_error_tp;
1302d88e 1686
514f1c67
ACM
1687 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1688 if (err < 0) {
c24ff998 1689 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
514f1c67
ACM
1690 goto out_delete_evlist;
1691 }
1692
752fde44
ACM
1693 err = trace__symbols_init(trace, evlist);
1694 if (err < 0) {
c24ff998 1695 fprintf(trace->output, "Problems initializing symbol libraries!\n");
3beb0861 1696 goto out_delete_maps;
752fde44
ACM
1697 }
1698
f77a9518 1699 perf_evlist__config(evlist, &trace->opts);
514f1c67 1700
f15eb531
NK
1701 signal(SIGCHLD, sig_handler);
1702 signal(SIGINT, sig_handler);
1703
1704 if (forks) {
6ef73ec4 1705 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
55e162ea 1706 argv, false, false);
f15eb531 1707 if (err < 0) {
c24ff998 1708 fprintf(trace->output, "Couldn't run the workload!\n");
3beb0861 1709 goto out_delete_maps;
f15eb531
NK
1710 }
1711 }
1712
514f1c67
ACM
1713 err = perf_evlist__open(evlist);
1714 if (err < 0) {
c24ff998 1715 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
3beb0861 1716 goto out_delete_maps;
514f1c67
ACM
1717 }
1718
1719 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1720 if (err < 0) {
c24ff998 1721 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
3beb0861 1722 goto out_close_evlist;
514f1c67
ACM
1723 }
1724
1725 perf_evlist__enable(evlist);
f15eb531
NK
1726
1727 if (forks)
1728 perf_evlist__start_workload(evlist);
1729
752fde44 1730 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
514f1c67 1731again:
efd5745e 1732 before = trace->nr_events;
514f1c67
ACM
1733
1734 for (i = 0; i < evlist->nr_mmaps; i++) {
1735 union perf_event *event;
1736
1737 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1738 const u32 type = event->header.type;
ba3d7dee 1739 tracepoint_handler handler;
514f1c67 1740 struct perf_sample sample;
514f1c67 1741
efd5745e 1742 ++trace->nr_events;
514f1c67 1743
514f1c67
ACM
1744 err = perf_evlist__parse_sample(evlist, event, &sample);
1745 if (err) {
c24ff998 1746 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
514f1c67
ACM
1747 continue;
1748 }
1749
4bb09192 1750 if (!trace->full_time && trace->base_time == 0)
752fde44
ACM
1751 trace->base_time = sample.time;
1752
1753 if (type != PERF_RECORD_SAMPLE) {
8fb598e5 1754 trace__process_event(trace, trace->host, event);
752fde44
ACM
1755 continue;
1756 }
1757
514f1c67
ACM
1758 evsel = perf_evlist__id2evsel(evlist, sample.id);
1759 if (evsel == NULL) {
c24ff998 1760 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
514f1c67
ACM
1761 continue;
1762 }
1763
fc551f8d 1764 if (sample.raw_data == NULL) {
c24ff998 1765 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
fc551f8d
ACM
1766 perf_evsel__name(evsel), sample.tid,
1767 sample.cpu, sample.raw_size);
1768 continue;
1769 }
1770
ba3d7dee
ACM
1771 handler = evsel->handler.func;
1772 handler(trace, evsel, &sample);
20c5f10e
ACM
1773
1774 if (done)
1775 goto out_unmap_evlist;
514f1c67
ACM
1776 }
1777 }
1778
efd5745e 1779 if (trace->nr_events == before) {
f15eb531 1780 if (done)
3beb0861 1781 goto out_unmap_evlist;
f15eb531 1782
514f1c67 1783 poll(evlist->pollfd, evlist->nr_fds, -1);
f15eb531
NK
1784 }
1785
1786 if (done)
1787 perf_evlist__disable(evlist);
c522739d
ACM
1788 else
1789 goto again;
514f1c67 1790
3beb0861 1791out_unmap_evlist:
c522739d
ACM
1792 if (!err) {
1793 if (trace->summary)
1794 trace__fprintf_thread_summary(trace, trace->output);
1795
1796 if (trace->show_tool_stats) {
1797 fprintf(trace->output, "Stats:\n "
1798 " vfs_getname : %" PRIu64 "\n"
1799 " proc_getname: %" PRIu64 "\n",
1800 trace->stats.vfs_getname,
1801 trace->stats.proc_getname);
1802 }
1803 }
bf2575c1 1804
3beb0861
NK
1805 perf_evlist__munmap(evlist);
1806out_close_evlist:
1807 perf_evlist__close(evlist);
1808out_delete_maps:
1809 perf_evlist__delete_maps(evlist);
514f1c67
ACM
1810out_delete_evlist:
1811 perf_evlist__delete(evlist);
1812out:
75b757ca 1813 trace->live = false;
514f1c67 1814 return err;
87f91868
RR
1815out_error_tp:
1816 switch(errno) {
1817 case ENOENT:
1818 fputs("Error:\tUnable to find debugfs\n"
1819 "Hint:\tWas your kernel was compiled with debugfs support?\n"
1820 "Hint:\tIs the debugfs filesystem mounted?\n"
1821 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'\n",
1822 trace->output);
1823 break;
1824 case EACCES:
1825 fprintf(trace->output,
1826 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1827 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1828 debugfs_mountpoint, debugfs_mountpoint);
1829 break;
1830 default: {
1831 char bf[256];
1832 fprintf(trace->output, "Can't trace: %s\n",
1833 strerror_r(errno, bf, sizeof(bf)));
1834 }
1835 break;
1836 }
1837 goto out_delete_evlist;
514f1c67
ACM
1838}
1839
6810fc91
DA
1840static int trace__replay(struct trace *trace)
1841{
1842 const struct perf_evsel_str_handler handlers[] = {
1843 { "raw_syscalls:sys_enter", trace__sys_enter, },
1844 { "raw_syscalls:sys_exit", trace__sys_exit, },
c522739d 1845 { "probe:vfs_getname", trace__vfs_getname, },
6810fc91
DA
1846 };
1847
1848 struct perf_session *session;
1849 int err = -1;
1850
1851 trace->tool.sample = trace__process_sample;
1852 trace->tool.mmap = perf_event__process_mmap;
384c671e 1853 trace->tool.mmap2 = perf_event__process_mmap2;
6810fc91
DA
1854 trace->tool.comm = perf_event__process_comm;
1855 trace->tool.exit = perf_event__process_exit;
1856 trace->tool.fork = perf_event__process_fork;
1857 trace->tool.attr = perf_event__process_attr;
1858 trace->tool.tracing_data = perf_event__process_tracing_data;
1859 trace->tool.build_id = perf_event__process_build_id;
1860
1861 trace->tool.ordered_samples = true;
1862 trace->tool.ordering_requires_timestamps = true;
1863
1864 /* add tid to output */
1865 trace->multiple_threads = true;
1866
1867 if (symbol__init() < 0)
1868 return -1;
1869
1870 session = perf_session__new(input_name, O_RDONLY, 0, false,
1871 &trace->tool);
1872 if (session == NULL)
1873 return -ENOMEM;
1874
8fb598e5
DA
1875 trace->host = &session->machines.host;
1876
6810fc91
DA
1877 err = perf_session__set_tracepoints_handlers(session, handlers);
1878 if (err)
1879 goto out;
1880
1881 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1882 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1883 goto out;
1884 }
1885
1886 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1887 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1888 goto out;
1889 }
1890
bdc89661
DA
1891 err = parse_target_str(trace);
1892 if (err != 0)
1893 goto out;
1894
6810fc91
DA
1895 setup_pager();
1896
1897 err = perf_session__process_events(session, &trace->tool);
1898 if (err)
1899 pr_err("Failed to process events, error %d", err);
1900
bf2575c1
DA
1901 else if (trace->summary)
1902 trace__fprintf_thread_summary(trace, trace->output);
1903
6810fc91
DA
1904out:
1905 perf_session__delete(session);
1906
1907 return err;
1908}
1909
1302d88e
ACM
1910static size_t trace__fprintf_threads_header(FILE *fp)
1911{
1912 size_t printed;
1913
bf2575c1
DA
1914 printed = fprintf(fp, "\n _____________________________________________________________________________\n");
1915 printed += fprintf(fp, " __) Summary of events (__\n\n");
1916 printed += fprintf(fp, " [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1917 printed += fprintf(fp, " syscall count min max avg stddev\n");
1918 printed += fprintf(fp, " msec msec msec %%\n");
1919 printed += fprintf(fp, " _____________________________________________________________________________\n\n");
1920
1921 return printed;
1922}
1923
1924static size_t thread__dump_stats(struct thread_trace *ttrace,
1925 struct trace *trace, FILE *fp)
1926{
1927 struct stats *stats;
1928 size_t printed = 0;
1929 struct syscall *sc;
1930 struct int_node *inode = intlist__first(ttrace->syscall_stats);
1931
1932 if (inode == NULL)
1933 return 0;
1934
1935 printed += fprintf(fp, "\n");
1936
1937 /* each int_node is a syscall */
1938 while (inode) {
1939 stats = inode->priv;
1940 if (stats) {
1941 double min = (double)(stats->min) / NSEC_PER_MSEC;
1942 double max = (double)(stats->max) / NSEC_PER_MSEC;
1943 double avg = avg_stats(stats);
1944 double pct;
1945 u64 n = (u64) stats->n;
1946
1947 pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
1948 avg /= NSEC_PER_MSEC;
1949
1950 sc = &trace->syscalls.table[inode->i];
1951 printed += fprintf(fp, "%24s %14s : ", "", sc->name);
1952 printed += fprintf(fp, "%5" PRIu64 " %8.3f %8.3f",
1953 n, min, max);
1954 printed += fprintf(fp, " %8.3f %6.2f\n", avg, pct);
1955 }
1956
1957 inode = intlist__next(inode);
1958 }
1959
1960 printed += fprintf(fp, "\n\n");
1302d88e
ACM
1961
1962 return printed;
1963}
1964
896cbb56
DA
1965/* struct used to pass data to per-thread function */
1966struct summary_data {
1967 FILE *fp;
1968 struct trace *trace;
1969 size_t printed;
1970};
1971
1972static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1973{
1974 struct summary_data *data = priv;
1975 FILE *fp = data->fp;
1976 size_t printed = data->printed;
1977 struct trace *trace = data->trace;
1978 struct thread_trace *ttrace = thread->priv;
1979 const char *color;
1980 double ratio;
1981
1982 if (ttrace == NULL)
1983 return 0;
1984
1985 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1986
1987 color = PERF_COLOR_NORMAL;
1988 if (ratio > 50.0)
1989 color = PERF_COLOR_RED;
1990 else if (ratio > 25.0)
1991 color = PERF_COLOR_GREEN;
1992 else if (ratio > 5.0)
1993 color = PERF_COLOR_YELLOW;
1994
1995 printed += color_fprintf(fp, color, "%20s", thread->comm);
1996 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1997 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1998 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
bf2575c1 1999 printed += thread__dump_stats(ttrace, trace, fp);
896cbb56
DA
2000
2001 data->printed += printed;
2002
2003 return 0;
2004}
2005
1302d88e
ACM
2006static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
2007{
896cbb56
DA
2008 struct summary_data data = {
2009 .fp = fp,
2010 .trace = trace
2011 };
2012 data.printed = trace__fprintf_threads_header(fp);
1302d88e 2013
896cbb56
DA
2014 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
2015
2016 return data.printed;
1302d88e
ACM
2017}
2018
ae9ed035
ACM
2019static int trace__set_duration(const struct option *opt, const char *str,
2020 int unset __maybe_unused)
2021{
2022 struct trace *trace = opt->value;
2023
2024 trace->duration_filter = atof(str);
2025 return 0;
2026}
2027
c24ff998
ACM
2028static int trace__open_output(struct trace *trace, const char *filename)
2029{
2030 struct stat st;
2031
2032 if (!stat(filename, &st) && st.st_size) {
2033 char oldname[PATH_MAX];
2034
2035 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
2036 unlink(oldname);
2037 rename(filename, oldname);
2038 }
2039
2040 trace->output = fopen(filename, "w");
2041
2042 return trace->output == NULL ? -errno : 0;
2043}
2044
514f1c67
ACM
2045int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
2046{
2047 const char * const trace_usage[] = {
f15eb531
NK
2048 "perf trace [<options>] [<command>]",
2049 "perf trace [<options>] -- <command> [<options>]",
5e2485b1
DA
2050 "perf trace record [<options>] [<command>]",
2051 "perf trace record [<options>] -- <command> [<options>]",
514f1c67
ACM
2052 NULL
2053 };
2054 struct trace trace = {
c522739d
ACM
2055 .audit = {
2056 .machine = audit_detect_machine(),
2057 .open_id = audit_name_to_syscall("open", trace.audit.machine),
2058 },
514f1c67
ACM
2059 .syscalls = {
2060 . max = -1,
2061 },
2062 .opts = {
2063 .target = {
2064 .uid = UINT_MAX,
2065 .uses_mmap = true,
2066 },
2067 .user_freq = UINT_MAX,
2068 .user_interval = ULLONG_MAX,
2069 .no_delay = true,
2070 .mmap_pages = 1024,
2071 },
c24ff998 2072 .output = stdout,
50c95cbd 2073 .show_comm = true,
514f1c67 2074 };
c24ff998 2075 const char *output_name = NULL;
2ae3a312 2076 const char *ev_qualifier_str = NULL;
514f1c67 2077 const struct option trace_options[] = {
50c95cbd
ACM
2078 OPT_BOOLEAN(0, "comm", &trace.show_comm,
2079 "show the thread COMM next to its id"),
c522739d 2080 OPT_BOOLEAN(0, "tool_stats", &trace.show_tool_stats, "show tool stats"),
2ae3a312
ACM
2081 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
2082 "list of events to trace"),
c24ff998 2083 OPT_STRING('o', "output", &output_name, "file", "output file name"),
6810fc91 2084 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
514f1c67
ACM
2085 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
2086 "trace events on existing process id"),
ac9be8ee 2087 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
514f1c67 2088 "trace events on existing thread id"),
ac9be8ee 2089 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
514f1c67 2090 "system-wide collection from all CPUs"),
ac9be8ee 2091 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
514f1c67 2092 "list of cpus to monitor"),
6810fc91 2093 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
514f1c67 2094 "child tasks do not inherit counters"),
994a1f78
JO
2095 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
2096 "number of mmap data pages",
2097 perf_evlist__parse_mmap_pages),
ac9be8ee 2098 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
514f1c67 2099 "user to profile"),
ae9ed035
ACM
2100 OPT_CALLBACK(0, "duration", &trace, "float",
2101 "show only events with duration > N.M ms",
2102 trace__set_duration),
1302d88e 2103 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
7c304ee0 2104 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
4bb09192
DA
2105 OPT_BOOLEAN('T', "time", &trace.full_time,
2106 "Show full timestamp, not time relative to first start"),
bf2575c1
DA
2107 OPT_BOOLEAN(0, "summary", &trace.summary,
2108 "Show syscall summary with statistics"),
514f1c67
ACM
2109 OPT_END()
2110 };
2111 int err;
32caf0d1 2112 char bf[BUFSIZ];
514f1c67 2113
5e2485b1
DA
2114 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
2115 return trace__record(argc-2, &argv[2]);
2116
514f1c67 2117 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
514f1c67 2118
c24ff998
ACM
2119 if (output_name != NULL) {
2120 err = trace__open_output(&trace, output_name);
2121 if (err < 0) {
2122 perror("failed to create output file");
2123 goto out;
2124 }
2125 }
2126
2ae3a312 2127 if (ev_qualifier_str != NULL) {
b059efdf
ACM
2128 const char *s = ev_qualifier_str;
2129
2130 trace.not_ev_qualifier = *s == '!';
2131 if (trace.not_ev_qualifier)
2132 ++s;
2133 trace.ev_qualifier = strlist__new(true, s);
2ae3a312 2134 if (trace.ev_qualifier == NULL) {
c24ff998
ACM
2135 fputs("Not enough memory to parse event qualifier",
2136 trace.output);
2137 err = -ENOMEM;
2138 goto out_close;
2ae3a312
ACM
2139 }
2140 }
2141
32caf0d1
NK
2142 err = perf_target__validate(&trace.opts.target);
2143 if (err) {
2144 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2145 fprintf(trace.output, "%s", bf);
2146 goto out_close;
32caf0d1
NK
2147 }
2148
514f1c67
ACM
2149 err = perf_target__parse_uid(&trace.opts.target);
2150 if (err) {
514f1c67 2151 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
c24ff998
ACM
2152 fprintf(trace.output, "%s", bf);
2153 goto out_close;
514f1c67
ACM
2154 }
2155
f15eb531 2156 if (!argc && perf_target__none(&trace.opts.target))
ee76120e
NK
2157 trace.opts.target.system_wide = true;
2158
6810fc91
DA
2159 if (input_name)
2160 err = trace__replay(&trace);
2161 else
2162 err = trace__run(&trace, argc, argv);
1302d88e 2163
c24ff998
ACM
2164out_close:
2165 if (output_name != NULL)
2166 fclose(trace.output);
2167out:
1302d88e 2168 return err;
514f1c67 2169}
This page took 0.155168 seconds and 5 git commands to generate.