blob: fcc157fce6c60dd71883715dc2edfb7130f0973b [file] [log] [blame]
Robert Richter4e319022013-06-11 17:29:18 +02001#include <traceevent/event-parse.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002#include "builtin.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03003#include "util/color.h"
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03004#include "util/debug.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03005#include "util/evlist.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03006#include "util/machine.h"
David Ahern6810fc92013-08-28 22:29:52 -06007#include "util/session.h"
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03008#include "util/thread.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03009#include "util/parse-options.h"
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -030010#include "util/strlist.h"
David Ahernbdc89662013-08-28 22:29:53 -060011#include "util/intlist.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030012#include "util/thread_map.h"
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030013
14#include <libaudit.h>
15#include <stdlib.h>
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -030016#include <sys/eventfd.h>
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030017#include <sys/mman.h>
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -030018#include <linux/futex.h>
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -030019
Ingo Molnar456857b2013-09-12 15:29:00 +020020/* For older distros: */
21#ifndef MAP_STACK
22# define MAP_STACK 0x20000
23#endif
24
25#ifndef MADV_HWPOISON
26# define MADV_HWPOISON 100
27#endif
28
29#ifndef MADV_MERGEABLE
30# define MADV_MERGEABLE 12
31#endif
32
33#ifndef MADV_UNMERGEABLE
34# define MADV_UNMERGEABLE 13
35#endif
36
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030037struct syscall_arg {
38 unsigned long val;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030039 struct thread *thread;
40 struct trace *trace;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030041 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030042 u8 idx;
43 u8 mask;
44};
45
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030046struct strarray {
47 int nr_entries;
48 const char **entries;
49};
50
51#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
52 .nr_entries = ARRAY_SIZE(array), \
53 .entries = array, \
54}
55
56static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
57 struct syscall_arg *arg)
58{
59 int idx = arg->val;
60 struct strarray *sa = arg->parm;
61
62 if (idx < 0 || idx >= sa->nr_entries)
63 return scnprintf(bf, size, "%d", idx);
64
65 return scnprintf(bf, size, "%s", sa->entries[idx]);
66}
67
68#define SCA_STRARRAY syscall_arg__scnprintf_strarray
69
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030070static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
71 struct syscall_arg *arg);
72
73#define SCA_FD syscall_arg__scnprintf_fd
74
75static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
76 struct syscall_arg *arg)
77{
78 int fd = arg->val;
79
80 if (fd == AT_FDCWD)
81 return scnprintf(bf, size, "CWD");
82
83 return syscall_arg__scnprintf_fd(bf, size, arg);
84}
85
86#define SCA_FDAT syscall_arg__scnprintf_fd_at
87
88static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
89 struct syscall_arg *arg);
90
91#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
92
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030093static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030094 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030095{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030096 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030097}
98
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030099#define SCA_HEX syscall_arg__scnprintf_hex
100
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300101static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300102 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300103{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300104 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300105
106 if (prot == PROT_NONE)
107 return scnprintf(bf, size, "NONE");
108#define P_MMAP_PROT(n) \
109 if (prot & PROT_##n) { \
110 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
111 prot &= ~PROT_##n; \
112 }
113
114 P_MMAP_PROT(EXEC);
115 P_MMAP_PROT(READ);
116 P_MMAP_PROT(WRITE);
117#ifdef PROT_SEM
118 P_MMAP_PROT(SEM);
119#endif
120 P_MMAP_PROT(GROWSDOWN);
121 P_MMAP_PROT(GROWSUP);
122#undef P_MMAP_PROT
123
124 if (prot)
125 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
126
127 return printed;
128}
129
130#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
131
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300132static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300133 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300134{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300135 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300136
137#define P_MMAP_FLAG(n) \
138 if (flags & MAP_##n) { \
139 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
140 flags &= ~MAP_##n; \
141 }
142
143 P_MMAP_FLAG(SHARED);
144 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400145#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300146 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400147#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300148 P_MMAP_FLAG(ANONYMOUS);
149 P_MMAP_FLAG(DENYWRITE);
150 P_MMAP_FLAG(EXECUTABLE);
151 P_MMAP_FLAG(FILE);
152 P_MMAP_FLAG(FIXED);
153 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600154#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300155 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600156#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300157 P_MMAP_FLAG(LOCKED);
158 P_MMAP_FLAG(NONBLOCK);
159 P_MMAP_FLAG(NORESERVE);
160 P_MMAP_FLAG(POPULATE);
161 P_MMAP_FLAG(STACK);
162#ifdef MAP_UNINITIALIZED
163 P_MMAP_FLAG(UNINITIALIZED);
164#endif
165#undef P_MMAP_FLAG
166
167 if (flags)
168 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
169
170 return printed;
171}
172
173#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
174
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300175static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300176 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300177{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300178 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300179
180 switch (behavior) {
181#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
182 P_MADV_BHV(NORMAL);
183 P_MADV_BHV(RANDOM);
184 P_MADV_BHV(SEQUENTIAL);
185 P_MADV_BHV(WILLNEED);
186 P_MADV_BHV(DONTNEED);
187 P_MADV_BHV(REMOVE);
188 P_MADV_BHV(DONTFORK);
189 P_MADV_BHV(DOFORK);
190 P_MADV_BHV(HWPOISON);
191#ifdef MADV_SOFT_OFFLINE
192 P_MADV_BHV(SOFT_OFFLINE);
193#endif
194 P_MADV_BHV(MERGEABLE);
195 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600196#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300197 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600198#endif
199#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300200 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600201#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300202#ifdef MADV_DONTDUMP
203 P_MADV_BHV(DONTDUMP);
204#endif
205#ifdef MADV_DODUMP
206 P_MADV_BHV(DODUMP);
207#endif
208#undef P_MADV_PHV
209 default: break;
210 }
211
212 return scnprintf(bf, size, "%#x", behavior);
213}
214
215#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
216
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300217static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
218 struct syscall_arg *arg)
219{
220 int printed = 0, op = arg->val;
221
222 if (op == 0)
223 return scnprintf(bf, size, "NONE");
224#define P_CMD(cmd) \
225 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
226 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
227 op &= ~LOCK_##cmd; \
228 }
229
230 P_CMD(SH);
231 P_CMD(EX);
232 P_CMD(NB);
233 P_CMD(UN);
234 P_CMD(MAND);
235 P_CMD(RW);
236 P_CMD(READ);
237 P_CMD(WRITE);
238#undef P_OP
239
240 if (op)
241 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
242
243 return printed;
244}
245
246#define SCA_FLOCK syscall_arg__scnprintf_flock
247
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300248static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg)
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300249{
250 enum syscall_futex_args {
251 SCF_UADDR = (1 << 0),
252 SCF_OP = (1 << 1),
253 SCF_VAL = (1 << 2),
254 SCF_TIMEOUT = (1 << 3),
255 SCF_UADDR2 = (1 << 4),
256 SCF_VAL3 = (1 << 5),
257 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300258 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300259 int cmd = op & FUTEX_CMD_MASK;
260 size_t printed = 0;
261
262 switch (cmd) {
263#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300264 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
265 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
266 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
267 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
268 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
269 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300270 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300271 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
272 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
273 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
274 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
275 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300276 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
277 default: printed = scnprintf(bf, size, "%#x", cmd); break;
278 }
279
280 if (op & FUTEX_PRIVATE_FLAG)
281 printed += scnprintf(bf + printed, size - printed, "|PRIV");
282
283 if (op & FUTEX_CLOCK_REALTIME)
284 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
285
286 return printed;
287}
288
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300289#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
290
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300291static const char *epoll_ctl_ops[] = { [1] = "ADD", "DEL", "MOD", };
292static DEFINE_STRARRAY(epoll_ctl_ops);
293
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300294static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
295static DEFINE_STRARRAY(itimers);
296
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300297static const char *whences[] = { "SET", "CUR", "END",
298#ifdef SEEK_DATA
299"DATA",
300#endif
301#ifdef SEEK_HOLE
302"HOLE",
303#endif
304};
305static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300306
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300307static const char *fcntl_cmds[] = {
308 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
309 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
310 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
311 "F_GETOWNER_UIDS",
312};
313static DEFINE_STRARRAY(fcntl_cmds);
314
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300315static const char *rlimit_resources[] = {
316 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
317 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
318 "RTTIME",
319};
320static DEFINE_STRARRAY(rlimit_resources);
321
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300322static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
323static DEFINE_STRARRAY(sighow);
324
David Ahern4f8c1b72013-09-22 19:45:00 -0600325static const char *clockid[] = {
326 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
327 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
328};
329static DEFINE_STRARRAY(clockid);
330
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300331static const char *socket_families[] = {
332 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
333 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
334 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
335 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
336 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
337 "ALG", "NFC", "VSOCK",
338};
339static DEFINE_STRARRAY(socket_families);
340
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300341#ifndef SOCK_TYPE_MASK
342#define SOCK_TYPE_MASK 0xf
343#endif
344
345static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
346 struct syscall_arg *arg)
347{
348 size_t printed;
349 int type = arg->val,
350 flags = type & ~SOCK_TYPE_MASK;
351
352 type &= SOCK_TYPE_MASK;
353 /*
354 * Can't use a strarray, MIPS may override for ABI reasons.
355 */
356 switch (type) {
357#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
358 P_SK_TYPE(STREAM);
359 P_SK_TYPE(DGRAM);
360 P_SK_TYPE(RAW);
361 P_SK_TYPE(RDM);
362 P_SK_TYPE(SEQPACKET);
363 P_SK_TYPE(DCCP);
364 P_SK_TYPE(PACKET);
365#undef P_SK_TYPE
366 default:
367 printed = scnprintf(bf, size, "%#x", type);
368 }
369
370#define P_SK_FLAG(n) \
371 if (flags & SOCK_##n) { \
372 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
373 flags &= ~SOCK_##n; \
374 }
375
376 P_SK_FLAG(CLOEXEC);
377 P_SK_FLAG(NONBLOCK);
378#undef P_SK_FLAG
379
380 if (flags)
381 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
382
383 return printed;
384}
385
386#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
387
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300388#ifndef MSG_PROBE
389#define MSG_PROBE 0x10
390#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600391#ifndef MSG_WAITFORONE
392#define MSG_WAITFORONE 0x10000
393#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300394#ifndef MSG_SENDPAGE_NOTLAST
395#define MSG_SENDPAGE_NOTLAST 0x20000
396#endif
397#ifndef MSG_FASTOPEN
398#define MSG_FASTOPEN 0x20000000
399#endif
400
401static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
402 struct syscall_arg *arg)
403{
404 int printed = 0, flags = arg->val;
405
406 if (flags == 0)
407 return scnprintf(bf, size, "NONE");
408#define P_MSG_FLAG(n) \
409 if (flags & MSG_##n) { \
410 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
411 flags &= ~MSG_##n; \
412 }
413
414 P_MSG_FLAG(OOB);
415 P_MSG_FLAG(PEEK);
416 P_MSG_FLAG(DONTROUTE);
417 P_MSG_FLAG(TRYHARD);
418 P_MSG_FLAG(CTRUNC);
419 P_MSG_FLAG(PROBE);
420 P_MSG_FLAG(TRUNC);
421 P_MSG_FLAG(DONTWAIT);
422 P_MSG_FLAG(EOR);
423 P_MSG_FLAG(WAITALL);
424 P_MSG_FLAG(FIN);
425 P_MSG_FLAG(SYN);
426 P_MSG_FLAG(CONFIRM);
427 P_MSG_FLAG(RST);
428 P_MSG_FLAG(ERRQUEUE);
429 P_MSG_FLAG(NOSIGNAL);
430 P_MSG_FLAG(MORE);
431 P_MSG_FLAG(WAITFORONE);
432 P_MSG_FLAG(SENDPAGE_NOTLAST);
433 P_MSG_FLAG(FASTOPEN);
434 P_MSG_FLAG(CMSG_CLOEXEC);
435#undef P_MSG_FLAG
436
437 if (flags)
438 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
439
440 return printed;
441}
442
443#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
444
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300445static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
446 struct syscall_arg *arg)
447{
448 size_t printed = 0;
449 int mode = arg->val;
450
451 if (mode == F_OK) /* 0 */
452 return scnprintf(bf, size, "F");
453#define P_MODE(n) \
454 if (mode & n##_OK) { \
455 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
456 mode &= ~n##_OK; \
457 }
458
459 P_MODE(R);
460 P_MODE(W);
461 P_MODE(X);
462#undef P_MODE
463
464 if (mode)
465 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
466
467 return printed;
468}
469
470#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
471
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300472static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300473 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300474{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300475 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300476
477 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300478 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300479
480 if (flags == 0)
481 return scnprintf(bf, size, "RDONLY");
482#define P_FLAG(n) \
483 if (flags & O_##n) { \
484 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
485 flags &= ~O_##n; \
486 }
487
488 P_FLAG(APPEND);
489 P_FLAG(ASYNC);
490 P_FLAG(CLOEXEC);
491 P_FLAG(CREAT);
492 P_FLAG(DIRECT);
493 P_FLAG(DIRECTORY);
494 P_FLAG(EXCL);
495 P_FLAG(LARGEFILE);
496 P_FLAG(NOATIME);
497 P_FLAG(NOCTTY);
498#ifdef O_NONBLOCK
499 P_FLAG(NONBLOCK);
500#elif O_NDELAY
501 P_FLAG(NDELAY);
502#endif
503#ifdef O_PATH
504 P_FLAG(PATH);
505#endif
506 P_FLAG(RDWR);
507#ifdef O_DSYNC
508 if ((flags & O_SYNC) == O_SYNC)
509 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
510 else {
511 P_FLAG(DSYNC);
512 }
513#else
514 P_FLAG(SYNC);
515#endif
516 P_FLAG(TRUNC);
517 P_FLAG(WRONLY);
518#undef P_FLAG
519
520 if (flags)
521 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
522
523 return printed;
524}
525
526#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
527
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300528static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
529 struct syscall_arg *arg)
530{
531 int printed = 0, flags = arg->val;
532
533 if (flags == 0)
534 return scnprintf(bf, size, "NONE");
535#define P_FLAG(n) \
536 if (flags & EFD_##n) { \
537 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
538 flags &= ~EFD_##n; \
539 }
540
541 P_FLAG(SEMAPHORE);
542 P_FLAG(CLOEXEC);
543 P_FLAG(NONBLOCK);
544#undef P_FLAG
545
546 if (flags)
547 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
548
549 return printed;
550}
551
552#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
553
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300554static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
555 struct syscall_arg *arg)
556{
557 int printed = 0, flags = arg->val;
558
559#define P_FLAG(n) \
560 if (flags & O_##n) { \
561 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
562 flags &= ~O_##n; \
563 }
564
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_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
576
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300577static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
578{
579 int sig = arg->val;
580
581 switch (sig) {
582#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
583 P_SIGNUM(HUP);
584 P_SIGNUM(INT);
585 P_SIGNUM(QUIT);
586 P_SIGNUM(ILL);
587 P_SIGNUM(TRAP);
588 P_SIGNUM(ABRT);
589 P_SIGNUM(BUS);
590 P_SIGNUM(FPE);
591 P_SIGNUM(KILL);
592 P_SIGNUM(USR1);
593 P_SIGNUM(SEGV);
594 P_SIGNUM(USR2);
595 P_SIGNUM(PIPE);
596 P_SIGNUM(ALRM);
597 P_SIGNUM(TERM);
598 P_SIGNUM(STKFLT);
599 P_SIGNUM(CHLD);
600 P_SIGNUM(CONT);
601 P_SIGNUM(STOP);
602 P_SIGNUM(TSTP);
603 P_SIGNUM(TTIN);
604 P_SIGNUM(TTOU);
605 P_SIGNUM(URG);
606 P_SIGNUM(XCPU);
607 P_SIGNUM(XFSZ);
608 P_SIGNUM(VTALRM);
609 P_SIGNUM(PROF);
610 P_SIGNUM(WINCH);
611 P_SIGNUM(IO);
612 P_SIGNUM(PWR);
613 P_SIGNUM(SYS);
614 default: break;
615 }
616
617 return scnprintf(bf, size, "%#x", sig);
618}
619
620#define SCA_SIGNUM syscall_arg__scnprintf_signum
621
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300622#define STRARRAY(arg, name, array) \
623 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
624 .arg_parm = { [arg] = &strarray__##array, }
625
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300626static struct syscall_fmt {
627 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300628 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300629 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300630 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300631 bool errmsg;
632 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300633 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300634} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300635 { .name = "access", .errmsg = true,
636 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300637 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300638 { .name = "brk", .hexret = true,
639 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600640 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300641 { .name = "close", .errmsg = true,
642 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300643 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300644 { .name = "dup", .errmsg = true,
645 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
646 { .name = "dup2", .errmsg = true,
647 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
648 { .name = "dup3", .errmsg = true,
649 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300650 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300651 { .name = "eventfd2", .errmsg = true,
652 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300653 { .name = "faccessat", .errmsg = true,
654 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
655 { .name = "fadvise64", .errmsg = true,
656 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
657 { .name = "fallocate", .errmsg = true,
658 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
659 { .name = "fchdir", .errmsg = true,
660 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
661 { .name = "fchmod", .errmsg = true,
662 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
663 { .name = "fchmodat", .errmsg = true,
664 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
665 { .name = "fchown", .errmsg = true,
666 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
667 { .name = "fchownat", .errmsg = true,
668 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
669 { .name = "fcntl", .errmsg = true,
670 .arg_scnprintf = { [0] = SCA_FD, /* fd */
671 [1] = SCA_STRARRAY, /* cmd */ },
672 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
673 { .name = "fdatasync", .errmsg = true,
674 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300675 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300676 .arg_scnprintf = { [0] = SCA_FD, /* fd */
677 [1] = SCA_FLOCK, /* cmd */ }, },
678 { .name = "fsetxattr", .errmsg = true,
679 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
680 { .name = "fstat", .errmsg = true, .alias = "newfstat",
681 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
682 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
683 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
684 { .name = "fstatfs", .errmsg = true,
685 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
686 { .name = "fsync", .errmsg = true,
687 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
688 { .name = "ftruncate", .errmsg = true,
689 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300690 { .name = "futex", .errmsg = true,
691 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300692 { .name = "futimesat", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
694 { .name = "getdents", .errmsg = true,
695 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
696 { .name = "getdents64", .errmsg = true,
697 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300698 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
699 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300700 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300701 .arg_scnprintf = { [0] = SCA_FD, /* fd */
702 [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300703 { .name = "kill", .errmsg = true,
704 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300705 { .name = "linkat", .errmsg = true,
706 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
707 { .name = "lseek", .errmsg = true,
708 .arg_scnprintf = { [0] = SCA_FD, /* fd */
709 [2] = SCA_STRARRAY, /* whence */ },
710 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300711 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300712 { .name = "madvise", .errmsg = true,
713 .arg_scnprintf = { [0] = SCA_HEX, /* start */
714 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300715 { .name = "mkdirat", .errmsg = true,
716 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
717 { .name = "mknodat", .errmsg = true,
718 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300719 { .name = "mlock", .errmsg = true,
720 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
721 { .name = "mlockall", .errmsg = true,
722 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300723 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300724 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300725 [2] = SCA_MMAP_PROT, /* prot */
726 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300727 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300728 .arg_scnprintf = { [0] = SCA_HEX, /* start */
729 [2] = SCA_MMAP_PROT, /* prot */ }, },
730 { .name = "mremap", .hexret = true,
731 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
732 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300733 { .name = "munlock", .errmsg = true,
734 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300735 { .name = "munmap", .errmsg = true,
736 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300737 { .name = "name_to_handle_at", .errmsg = true,
738 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
739 { .name = "newfstatat", .errmsg = true,
740 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300741 { .name = "open", .errmsg = true,
742 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300743 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300744 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
745 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300746 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300747 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
748 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300749 { .name = "pipe2", .errmsg = true,
750 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300751 { .name = "poll", .errmsg = true, .timeout = true, },
752 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300753 { .name = "pread", .errmsg = true, .alias = "pread64",
754 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
755 { .name = "preadv", .errmsg = true, .alias = "pread",
756 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300757 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300758 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
759 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
760 { .name = "pwritev", .errmsg = true,
761 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
762 { .name = "read", .errmsg = true,
763 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
764 { .name = "readlinkat", .errmsg = true,
765 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
766 { .name = "readv", .errmsg = true,
767 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300768 { .name = "recvfrom", .errmsg = true,
769 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
770 { .name = "recvmmsg", .errmsg = true,
771 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
772 { .name = "recvmsg", .errmsg = true,
773 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300774 { .name = "renameat", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300776 { .name = "rt_sigaction", .errmsg = true,
777 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300778 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300779 { .name = "rt_sigqueueinfo", .errmsg = true,
780 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
781 { .name = "rt_tgsigqueueinfo", .errmsg = true,
782 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300783 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300784 { .name = "sendmmsg", .errmsg = true,
785 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
786 { .name = "sendmsg", .errmsg = true,
787 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
788 { .name = "sendto", .errmsg = true,
789 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300790 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
791 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300792 { .name = "shutdown", .errmsg = true,
793 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300794 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300795 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
796 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300797 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300798 { .name = "socketpair", .errmsg = true,
799 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
800 [1] = SCA_SK_TYPE, /* type */ },
801 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300802 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300803 { .name = "symlinkat", .errmsg = true,
804 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300805 { .name = "tgkill", .errmsg = true,
806 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
807 { .name = "tkill", .errmsg = true,
808 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300809 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300810 { .name = "unlinkat", .errmsg = true,
811 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
812 { .name = "utimensat", .errmsg = true,
813 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
814 { .name = "write", .errmsg = true,
815 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
816 { .name = "writev", .errmsg = true,
817 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300818};
819
820static int syscall_fmt__cmp(const void *name, const void *fmtp)
821{
822 const struct syscall_fmt *fmt = fmtp;
823 return strcmp(name, fmt->name);
824}
825
826static struct syscall_fmt *syscall_fmt__find(const char *name)
827{
828 const int nmemb = ARRAY_SIZE(syscall_fmts);
829 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
830}
831
832struct syscall {
833 struct event_format *tp_format;
834 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300835 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300836 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300837 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300838 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300839};
840
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200841static size_t fprintf_duration(unsigned long t, FILE *fp)
842{
843 double duration = (double)t / NSEC_PER_MSEC;
844 size_t printed = fprintf(fp, "(");
845
846 if (duration >= 1.0)
847 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
848 else if (duration >= 0.01)
849 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
850 else
851 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300852 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200853}
854
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300855struct thread_trace {
856 u64 entry_time;
857 u64 exit_time;
858 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300859 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300860 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300861 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300862 struct {
863 int max;
864 char **table;
865 } paths;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300866};
867
868static struct thread_trace *thread_trace__new(void)
869{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300870 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
871
872 if (ttrace)
873 ttrace->paths.max = -1;
874
875 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300876}
877
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300878static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300879{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300880 struct thread_trace *ttrace;
881
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300882 if (thread == NULL)
883 goto fail;
884
885 if (thread->priv == NULL)
886 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300887
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300888 if (thread->priv == NULL)
889 goto fail;
890
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300891 ttrace = thread->priv;
892 ++ttrace->nr_events;
893
894 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300895fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300896 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300897 "WARNING: not enough memory, dropping samples!\n");
898 return NULL;
899}
900
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300901struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300902 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300903 int audit_machine;
904 struct {
905 int max;
906 struct syscall *table;
907 } syscalls;
908 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909 struct machine host;
910 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600911 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300912 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300913 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300914 struct strlist *ev_qualifier;
915 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300916 bool live;
David Ahernbdc89662013-08-28 22:29:53 -0600917 struct intlist *tid_list;
918 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300919 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300920 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300921 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300922 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300923 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300924};
925
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300926static int thread__read_fd_path(struct thread *thread, int fd)
927{
928 struct thread_trace *ttrace = thread->priv;
929 char linkname[PATH_MAX], pathname[PATH_MAX];
930 struct stat st;
931 int ret;
932
933 if (thread->pid_ == thread->tid) {
934 scnprintf(linkname, sizeof(linkname),
935 "/proc/%d/fd/%d", thread->pid_, fd);
936 } else {
937 scnprintf(linkname, sizeof(linkname),
938 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
939 }
940
941 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
942 return -1;
943
944 ret = readlink(linkname, pathname, sizeof(pathname));
945
946 if (ret < 0 || ret > st.st_size)
947 return -1;
948
949 pathname[ret] = '\0';
950
951 if (fd > ttrace->paths.max) {
952 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
953
954 if (npath == NULL)
955 return -1;
956
957 if (ttrace->paths.max != -1) {
958 memset(npath + ttrace->paths.max + 1, 0,
959 (fd - ttrace->paths.max) * sizeof(char *));
960 } else {
961 memset(npath, 0, (fd + 1) * sizeof(char *));
962 }
963
964 ttrace->paths.table = npath;
965 ttrace->paths.max = fd;
966 }
967
968 ttrace->paths.table[fd] = strdup(pathname);
969
970 return ttrace->paths.table[fd] != NULL ? 0 : -1;
971}
972
973static const char *thread__fd_path(struct thread *thread, int fd, bool live)
974{
975 struct thread_trace *ttrace = thread->priv;
976
977 if (ttrace == NULL)
978 return NULL;
979
980 if (fd < 0)
981 return NULL;
982
983 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
984 (!live || thread__read_fd_path(thread, fd)))
985 return NULL;
986
987 return ttrace->paths.table[fd];
988}
989
990static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
991 struct syscall_arg *arg)
992{
993 int fd = arg->val;
994 size_t printed = scnprintf(bf, size, "%d", fd);
995 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
996
997 if (path)
998 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
999
1000 return printed;
1001}
1002
1003static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1004 struct syscall_arg *arg)
1005{
1006 int fd = arg->val;
1007 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1008 struct thread_trace *ttrace = arg->thread->priv;
1009
1010 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1011 free(ttrace->paths.table[fd]);
1012 ttrace->paths.table[fd] = NULL;
1013 }
1014
1015 return printed;
1016}
1017
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001018static bool trace__filter_duration(struct trace *trace, double t)
1019{
1020 return t < (trace->duration_filter * NSEC_PER_MSEC);
1021}
1022
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001023static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1024{
1025 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1026
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001027 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001028}
1029
Namhyung Kimf15eb532012-10-05 14:02:16 +09001030static bool done = false;
1031
1032static void sig_handler(int sig __maybe_unused)
1033{
1034 done = true;
1035}
1036
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001037static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001038 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001039{
1040 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001041 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001042
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001043 if (trace->multiple_threads) {
1044 if (trace->show_comm)
1045 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001046 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001047 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001048
1049 return printed;
1050}
1051
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001052static int trace__process_event(struct trace *trace, struct machine *machine,
1053 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001054{
1055 int ret = 0;
1056
1057 switch (event->header.type) {
1058 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001059 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001060 "LOST %" PRIu64 " events!\n", event->lost.lost);
1061 ret = machine__process_lost_event(machine, event);
1062 default:
1063 ret = machine__process_event(machine, event);
1064 break;
1065 }
1066
1067 return ret;
1068}
1069
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001070static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001071 union perf_event *event,
1072 struct perf_sample *sample __maybe_unused,
1073 struct machine *machine)
1074{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001075 struct trace *trace = container_of(tool, struct trace, tool);
1076 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001077}
1078
1079static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1080{
1081 int err = symbol__init();
1082
1083 if (err)
1084 return err;
1085
1086 machine__init(&trace->host, "", HOST_KERNEL_ID);
1087 machine__create_kernel_maps(&trace->host);
1088
1089 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001090 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001091 trace__tool_process,
1092 &trace->host);
1093 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001094 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001095 &trace->host);
1096 }
1097
1098 if (err)
1099 symbol__exit();
1100
1101 return err;
1102}
1103
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001104static int syscall__set_arg_fmts(struct syscall *sc)
1105{
1106 struct format_field *field;
1107 int idx = 0;
1108
1109 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1110 if (sc->arg_scnprintf == NULL)
1111 return -1;
1112
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001113 if (sc->fmt)
1114 sc->arg_parm = sc->fmt->arg_parm;
1115
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001116 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001117 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1118 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1119 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001120 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1121 ++idx;
1122 }
1123
1124 return 0;
1125}
1126
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001127static int trace__read_syscall_info(struct trace *trace, int id)
1128{
1129 char tp_name[128];
1130 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001131 const char *name = audit_syscall_to_name(id, trace->audit_machine);
1132
1133 if (name == NULL)
1134 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001135
1136 if (id > trace->syscalls.max) {
1137 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1138
1139 if (nsyscalls == NULL)
1140 return -1;
1141
1142 if (trace->syscalls.max != -1) {
1143 memset(nsyscalls + trace->syscalls.max + 1, 0,
1144 (id - trace->syscalls.max) * sizeof(*sc));
1145 } else {
1146 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1147 }
1148
1149 trace->syscalls.table = nsyscalls;
1150 trace->syscalls.max = id;
1151 }
1152
1153 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001154 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001155
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001156 if (trace->ev_qualifier) {
1157 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1158
1159 if (!(in ^ trace->not_ev_qualifier)) {
1160 sc->filtered = true;
1161 /*
1162 * No need to do read tracepoint information since this will be
1163 * filtered out.
1164 */
1165 return 0;
1166 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001167 }
1168
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001169 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001170
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001171 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1172 sc->tp_format = event_format__new("syscalls", tp_name);
1173
1174 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1175 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1176 sc->tp_format = event_format__new("syscalls", tp_name);
1177 }
1178
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001179 if (sc->tp_format == NULL)
1180 return -1;
1181
1182 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001183}
1184
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001185static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001186 unsigned long *args, struct trace *trace,
1187 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001188{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001189 size_t printed = 0;
1190
1191 if (sc->tp_format != NULL) {
1192 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001193 u8 bit = 1;
1194 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001195 .idx = 0,
1196 .mask = 0,
1197 .trace = trace,
1198 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001199 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001200
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001201 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001202 field = field->next, ++arg.idx, bit <<= 1) {
1203 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001204 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001205 /*
1206 * Suppress this argument if its value is zero and
1207 * and we don't have a string associated in an
1208 * strarray for it.
1209 */
1210 if (args[arg.idx] == 0 &&
1211 !(sc->arg_scnprintf &&
1212 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1213 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001214 continue;
1215
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001216 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001217 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001218 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1219 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001220 if (sc->arg_parm)
1221 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001222 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1223 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001224 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001225 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001226 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001227 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001228 }
1229 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001230 int i = 0;
1231
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001232 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001233 printed += scnprintf(bf + printed, size - printed,
1234 "%sarg%d: %ld",
1235 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001236 ++i;
1237 }
1238 }
1239
1240 return printed;
1241}
1242
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001243typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1244 struct perf_sample *sample);
1245
1246static struct syscall *trace__syscall_info(struct trace *trace,
1247 struct perf_evsel *evsel,
1248 struct perf_sample *sample)
1249{
1250 int id = perf_evsel__intval(evsel, sample, "id");
1251
1252 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001253
1254 /*
1255 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1256 * before that, leaving at a higher verbosity level till that is
1257 * explained. Reproduced with plain ftrace with:
1258 *
1259 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1260 * grep "NR -1 " /t/trace_pipe
1261 *
1262 * After generating some load on the machine.
1263 */
1264 if (verbose > 1) {
1265 static u64 n;
1266 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1267 id, perf_evsel__name(evsel), ++n);
1268 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001269 return NULL;
1270 }
1271
1272 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1273 trace__read_syscall_info(trace, id))
1274 goto out_cant_read;
1275
1276 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1277 goto out_cant_read;
1278
1279 return &trace->syscalls.table[id];
1280
1281out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001282 if (verbose) {
1283 fprintf(trace->output, "Problems reading syscall %d", id);
1284 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1285 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1286 fputs(" information\n", trace->output);
1287 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001288 return NULL;
1289}
1290
1291static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1292 struct perf_sample *sample)
1293{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001294 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001295 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001296 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001297 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001298 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001299 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001300
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001301 if (sc == NULL)
1302 return -1;
1303
1304 if (sc->filtered)
1305 return 0;
1306
Adrian Hunter314add62013-08-27 11:23:03 +03001307 thread = machine__findnew_thread(&trace->host, sample->pid,
1308 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001309 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001310 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001311 return -1;
1312
1313 args = perf_evsel__rawptr(evsel, sample, "args");
1314 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001315 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001316 return -1;
1317 }
1318
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001319 ttrace = thread->priv;
1320
1321 if (ttrace->entry_str == NULL) {
1322 ttrace->entry_str = malloc(1024);
1323 if (!ttrace->entry_str)
1324 return -1;
1325 }
1326
1327 ttrace->entry_time = sample->time;
1328 msg = ttrace->entry_str;
1329 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1330
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001331 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1332 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001333
1334 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001335 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001336 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1337 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001338 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001339 } else
1340 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001341
1342 return 0;
1343}
1344
1345static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1346 struct perf_sample *sample)
1347{
1348 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001349 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001350 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001351 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001352 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001353
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001354 if (sc == NULL)
1355 return -1;
1356
1357 if (sc->filtered)
1358 return 0;
1359
Adrian Hunter314add62013-08-27 11:23:03 +03001360 thread = machine__findnew_thread(&trace->host, sample->pid,
1361 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001362 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001363 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001364 return -1;
1365
1366 ret = perf_evsel__intval(evsel, sample, "ret");
1367
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001368 ttrace = thread->priv;
1369
1370 ttrace->exit_time = sample->time;
1371
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001372 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001373 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001374 if (trace__filter_duration(trace, duration))
1375 goto out;
1376 } else if (trace->duration_filter)
1377 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001378
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001379 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001380
1381 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001382 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001383 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001384 fprintf(trace->output, " ... [");
1385 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1386 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001387 }
1388
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001389 if (sc->fmt == NULL) {
1390signed_print:
1391 fprintf(trace->output, ") = %d", ret);
1392 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001393 char bf[256];
1394 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1395 *e = audit_errno_to_name(-ret);
1396
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001397 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001398 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001399 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001400 else if (sc->fmt->hexret)
1401 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001402 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001403 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001404
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001405 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001406out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001407 ttrace->entry_pending = false;
1408
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001409 return 0;
1410}
1411
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001412static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1413 struct perf_sample *sample)
1414{
1415 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1416 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001417 struct thread *thread = machine__findnew_thread(&trace->host,
1418 sample->pid,
1419 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001420 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001421
1422 if (ttrace == NULL)
1423 goto out_dump;
1424
1425 ttrace->runtime_ms += runtime_ms;
1426 trace->runtime_ms += runtime_ms;
1427 return 0;
1428
1429out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001430 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001431 evsel->name,
1432 perf_evsel__strval(evsel, sample, "comm"),
1433 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1434 runtime,
1435 perf_evsel__intval(evsel, sample, "vruntime"));
1436 return 0;
1437}
1438
David Ahernbdc89662013-08-28 22:29:53 -06001439static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1440{
1441 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1442 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1443 return false;
1444
1445 if (trace->pid_list || trace->tid_list)
1446 return true;
1447
1448 return false;
1449}
1450
David Ahern6810fc92013-08-28 22:29:52 -06001451static int trace__process_sample(struct perf_tool *tool,
1452 union perf_event *event __maybe_unused,
1453 struct perf_sample *sample,
1454 struct perf_evsel *evsel,
1455 struct machine *machine __maybe_unused)
1456{
1457 struct trace *trace = container_of(tool, struct trace, tool);
1458 int err = 0;
1459
1460 tracepoint_handler handler = evsel->handler.func;
1461
David Ahernbdc89662013-08-28 22:29:53 -06001462 if (skip_sample(trace, sample))
1463 return 0;
1464
David Ahern4bb09192013-09-04 12:37:43 -06001465 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001466 trace->base_time = sample->time;
1467
1468 if (handler)
1469 handler(trace, evsel, sample);
1470
1471 return err;
1472}
1473
1474static bool
1475perf_session__has_tp(struct perf_session *session, const char *name)
1476{
1477 struct perf_evsel *evsel;
1478
1479 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1480
1481 return evsel != NULL;
1482}
1483
David Ahernbdc89662013-08-28 22:29:53 -06001484static int parse_target_str(struct trace *trace)
1485{
1486 if (trace->opts.target.pid) {
1487 trace->pid_list = intlist__new(trace->opts.target.pid);
1488 if (trace->pid_list == NULL) {
1489 pr_err("Error parsing process id string\n");
1490 return -EINVAL;
1491 }
1492 }
1493
1494 if (trace->opts.target.tid) {
1495 trace->tid_list = intlist__new(trace->opts.target.tid);
1496 if (trace->tid_list == NULL) {
1497 pr_err("Error parsing thread id string\n");
1498 return -EINVAL;
1499 }
1500 }
1501
1502 return 0;
1503}
1504
Namhyung Kimf15eb532012-10-05 14:02:16 +09001505static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001506{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001507 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001508 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001509 int err = -1, i;
1510 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001511 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001512
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001513 trace->live = true;
1514
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001515 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001516 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001517 goto out;
1518 }
1519
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001520 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1521 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001522 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523 goto out_delete_evlist;
1524 }
1525
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001526 if (trace->sched &&
1527 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1528 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001529 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001530 goto out_delete_evlist;
1531 }
1532
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001533 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1534 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001535 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001536 goto out_delete_evlist;
1537 }
1538
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001539 err = trace__symbols_init(trace, evlist);
1540 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001541 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001542 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001543 }
1544
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001545 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001546
Namhyung Kimf15eb532012-10-05 14:02:16 +09001547 signal(SIGCHLD, sig_handler);
1548 signal(SIGINT, sig_handler);
1549
1550 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001551 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001552 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001553 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001554 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001555 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001556 }
1557 }
1558
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001559 err = perf_evlist__open(evlist);
1560 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001561 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001562 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001563 }
1564
1565 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1566 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001567 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001568 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001569 }
1570
1571 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001572
1573 if (forks)
1574 perf_evlist__start_workload(evlist);
1575
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001576 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001577again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001578 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001579
1580 for (i = 0; i < evlist->nr_mmaps; i++) {
1581 union perf_event *event;
1582
1583 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1584 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001585 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001586 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001587
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001588 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001589
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001590 err = perf_evlist__parse_sample(evlist, event, &sample);
1591 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001592 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001593 continue;
1594 }
1595
David Ahern4bb09192013-09-04 12:37:43 -06001596 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001597 trace->base_time = sample.time;
1598
1599 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001600 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001601 continue;
1602 }
1603
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001604 evsel = perf_evlist__id2evsel(evlist, sample.id);
1605 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001606 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001607 continue;
1608 }
1609
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001610 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001611 fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001612 perf_evsel__name(evsel), sample.tid,
1613 sample.cpu, sample.raw_size);
1614 continue;
1615 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001616
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001617 handler = evsel->handler.func;
1618 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001619
1620 if (done)
1621 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001622 }
1623 }
1624
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001625 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001626 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001627 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001628
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001629 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001630 }
1631
1632 if (done)
1633 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001634
1635 goto again;
1636
Namhyung Kim3beb0862013-03-15 14:48:50 +09001637out_unmap_evlist:
1638 perf_evlist__munmap(evlist);
1639out_close_evlist:
1640 perf_evlist__close(evlist);
1641out_delete_maps:
1642 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001643out_delete_evlist:
1644 perf_evlist__delete(evlist);
1645out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001646 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001647 return err;
1648}
1649
David Ahern6810fc92013-08-28 22:29:52 -06001650static int trace__replay(struct trace *trace)
1651{
1652 const struct perf_evsel_str_handler handlers[] = {
1653 { "raw_syscalls:sys_enter", trace__sys_enter, },
1654 { "raw_syscalls:sys_exit", trace__sys_exit, },
1655 };
1656
1657 struct perf_session *session;
1658 int err = -1;
1659
1660 trace->tool.sample = trace__process_sample;
1661 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001662 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001663 trace->tool.comm = perf_event__process_comm;
1664 trace->tool.exit = perf_event__process_exit;
1665 trace->tool.fork = perf_event__process_fork;
1666 trace->tool.attr = perf_event__process_attr;
1667 trace->tool.tracing_data = perf_event__process_tracing_data;
1668 trace->tool.build_id = perf_event__process_build_id;
1669
1670 trace->tool.ordered_samples = true;
1671 trace->tool.ordering_requires_timestamps = true;
1672
1673 /* add tid to output */
1674 trace->multiple_threads = true;
1675
1676 if (symbol__init() < 0)
1677 return -1;
1678
1679 session = perf_session__new(input_name, O_RDONLY, 0, false,
1680 &trace->tool);
1681 if (session == NULL)
1682 return -ENOMEM;
1683
1684 err = perf_session__set_tracepoints_handlers(session, handlers);
1685 if (err)
1686 goto out;
1687
1688 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1689 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1690 goto out;
1691 }
1692
1693 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1694 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1695 goto out;
1696 }
1697
David Ahernbdc89662013-08-28 22:29:53 -06001698 err = parse_target_str(trace);
1699 if (err != 0)
1700 goto out;
1701
David Ahern6810fc92013-08-28 22:29:52 -06001702 setup_pager();
1703
1704 err = perf_session__process_events(session, &trace->tool);
1705 if (err)
1706 pr_err("Failed to process events, error %d", err);
1707
1708out:
1709 perf_session__delete(session);
1710
1711 return err;
1712}
1713
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001714static size_t trace__fprintf_threads_header(FILE *fp)
1715{
1716 size_t printed;
1717
1718 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1719 printed += fprintf(fp," __) Summary of events (__\n\n");
1720 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1721 printed += fprintf(fp," _____________________________________________________________________\n\n");
1722
1723 return printed;
1724}
1725
1726static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1727{
1728 size_t printed = trace__fprintf_threads_header(fp);
1729 struct rb_node *nd;
1730
1731 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1732 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1733 struct thread_trace *ttrace = thread->priv;
1734 const char *color;
1735 double ratio;
1736
1737 if (ttrace == NULL)
1738 continue;
1739
1740 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1741
1742 color = PERF_COLOR_NORMAL;
1743 if (ratio > 50.0)
1744 color = PERF_COLOR_RED;
1745 else if (ratio > 25.0)
1746 color = PERF_COLOR_GREEN;
1747 else if (ratio > 5.0)
1748 color = PERF_COLOR_YELLOW;
1749
1750 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001751 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001752 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1753 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1754 }
1755
1756 return printed;
1757}
1758
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001759static int trace__set_duration(const struct option *opt, const char *str,
1760 int unset __maybe_unused)
1761{
1762 struct trace *trace = opt->value;
1763
1764 trace->duration_filter = atof(str);
1765 return 0;
1766}
1767
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001768static int trace__open_output(struct trace *trace, const char *filename)
1769{
1770 struct stat st;
1771
1772 if (!stat(filename, &st) && st.st_size) {
1773 char oldname[PATH_MAX];
1774
1775 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1776 unlink(oldname);
1777 rename(filename, oldname);
1778 }
1779
1780 trace->output = fopen(filename, "w");
1781
1782 return trace->output == NULL ? -errno : 0;
1783}
1784
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001785int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1786{
1787 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001788 "perf trace [<options>] [<command>]",
1789 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001790 NULL
1791 };
1792 struct trace trace = {
1793 .audit_machine = audit_detect_machine(),
1794 .syscalls = {
1795 . max = -1,
1796 },
1797 .opts = {
1798 .target = {
1799 .uid = UINT_MAX,
1800 .uses_mmap = true,
1801 },
1802 .user_freq = UINT_MAX,
1803 .user_interval = ULLONG_MAX,
1804 .no_delay = true,
1805 .mmap_pages = 1024,
1806 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001807 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001808 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001809 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001810 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001811 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001812 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001813 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1814 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001815 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1816 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001817 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001818 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001819 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1820 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001821 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001822 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001823 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001824 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001825 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001826 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001827 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001828 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001829 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1830 "number of mmap data pages",
1831 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001832 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001833 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001834 OPT_CALLBACK(0, "duration", &trace, "float",
1835 "show only events with duration > N.M ms",
1836 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001837 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001838 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001839 OPT_BOOLEAN('T', "time", &trace.full_time,
1840 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001841 OPT_END()
1842 };
1843 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001844 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001845
1846 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001847
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001848 if (output_name != NULL) {
1849 err = trace__open_output(&trace, output_name);
1850 if (err < 0) {
1851 perror("failed to create output file");
1852 goto out;
1853 }
1854 }
1855
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001856 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001857 const char *s = ev_qualifier_str;
1858
1859 trace.not_ev_qualifier = *s == '!';
1860 if (trace.not_ev_qualifier)
1861 ++s;
1862 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001863 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001864 fputs("Not enough memory to parse event qualifier",
1865 trace.output);
1866 err = -ENOMEM;
1867 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001868 }
1869 }
1870
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001871 err = perf_target__validate(&trace.opts.target);
1872 if (err) {
1873 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001874 fprintf(trace.output, "%s", bf);
1875 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001876 }
1877
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001878 err = perf_target__parse_uid(&trace.opts.target);
1879 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001880 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001881 fprintf(trace.output, "%s", bf);
1882 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001883 }
1884
Namhyung Kimf15eb532012-10-05 14:02:16 +09001885 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001886 trace.opts.target.system_wide = true;
1887
David Ahern6810fc92013-08-28 22:29:52 -06001888 if (input_name)
1889 err = trace__replay(&trace);
1890 else
1891 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001892
1893 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001894 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001895
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001896out_close:
1897 if (output_name != NULL)
1898 fclose(trace.output);
1899out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001900 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001901}