blob: 0d4af1d7e55c4da0cf930bef853c8fe9ec5d0d9b [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 {
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030047 int offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030048 int nr_entries;
49 const char **entries;
50};
51
52#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
53 .nr_entries = ARRAY_SIZE(array), \
54 .entries = array, \
55}
56
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030057#define DEFINE_STRARRAY_OFFSET(array, off) struct strarray strarray__##array = { \
58 .offset = off, \
59 .nr_entries = ARRAY_SIZE(array), \
60 .entries = array, \
61}
62
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -030063static size_t __syscall_arg__scnprintf_strarray(char *bf, size_t size,
64 const char *intfmt,
65 struct syscall_arg *arg)
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030066{
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030067 struct strarray *sa = arg->parm;
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -030068 int idx = arg->val - sa->offset;
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030069
70 if (idx < 0 || idx >= sa->nr_entries)
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -030071 return scnprintf(bf, size, intfmt, arg->val);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030072
73 return scnprintf(bf, size, "%s", sa->entries[idx]);
74}
75
Arnaldo Carvalho de Melo975b7c22013-10-08 17:17:43 -030076static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
77 struct syscall_arg *arg)
78{
79 return __syscall_arg__scnprintf_strarray(bf, size, "%d", arg);
80}
81
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030082#define SCA_STRARRAY syscall_arg__scnprintf_strarray
83
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030084static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
85 struct syscall_arg *arg);
86
87#define SCA_FD syscall_arg__scnprintf_fd
88
89static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
90 struct syscall_arg *arg)
91{
92 int fd = arg->val;
93
94 if (fd == AT_FDCWD)
95 return scnprintf(bf, size, "CWD");
96
97 return syscall_arg__scnprintf_fd(bf, size, arg);
98}
99
100#define SCA_FDAT syscall_arg__scnprintf_fd_at
101
102static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
103 struct syscall_arg *arg);
104
105#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
106
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300107static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300108 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300109{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300110 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300111}
112
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300113#define SCA_HEX syscall_arg__scnprintf_hex
114
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300115static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300116 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300117{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300118 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300119
120 if (prot == PROT_NONE)
121 return scnprintf(bf, size, "NONE");
122#define P_MMAP_PROT(n) \
123 if (prot & PROT_##n) { \
124 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
125 prot &= ~PROT_##n; \
126 }
127
128 P_MMAP_PROT(EXEC);
129 P_MMAP_PROT(READ);
130 P_MMAP_PROT(WRITE);
131#ifdef PROT_SEM
132 P_MMAP_PROT(SEM);
133#endif
134 P_MMAP_PROT(GROWSDOWN);
135 P_MMAP_PROT(GROWSUP);
136#undef P_MMAP_PROT
137
138 if (prot)
139 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
140
141 return printed;
142}
143
144#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
145
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300146static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300147 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300148{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300149 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300150
151#define P_MMAP_FLAG(n) \
152 if (flags & MAP_##n) { \
153 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
154 flags &= ~MAP_##n; \
155 }
156
157 P_MMAP_FLAG(SHARED);
158 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400159#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300160 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400161#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300162 P_MMAP_FLAG(ANONYMOUS);
163 P_MMAP_FLAG(DENYWRITE);
164 P_MMAP_FLAG(EXECUTABLE);
165 P_MMAP_FLAG(FILE);
166 P_MMAP_FLAG(FIXED);
167 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600168#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300169 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600170#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300171 P_MMAP_FLAG(LOCKED);
172 P_MMAP_FLAG(NONBLOCK);
173 P_MMAP_FLAG(NORESERVE);
174 P_MMAP_FLAG(POPULATE);
175 P_MMAP_FLAG(STACK);
176#ifdef MAP_UNINITIALIZED
177 P_MMAP_FLAG(UNINITIALIZED);
178#endif
179#undef P_MMAP_FLAG
180
181 if (flags)
182 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
183
184 return printed;
185}
186
187#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
188
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300189static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300190 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300191{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300192 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300193
194 switch (behavior) {
195#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
196 P_MADV_BHV(NORMAL);
197 P_MADV_BHV(RANDOM);
198 P_MADV_BHV(SEQUENTIAL);
199 P_MADV_BHV(WILLNEED);
200 P_MADV_BHV(DONTNEED);
201 P_MADV_BHV(REMOVE);
202 P_MADV_BHV(DONTFORK);
203 P_MADV_BHV(DOFORK);
204 P_MADV_BHV(HWPOISON);
205#ifdef MADV_SOFT_OFFLINE
206 P_MADV_BHV(SOFT_OFFLINE);
207#endif
208 P_MADV_BHV(MERGEABLE);
209 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600210#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300211 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600212#endif
213#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300214 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600215#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300216#ifdef MADV_DONTDUMP
217 P_MADV_BHV(DONTDUMP);
218#endif
219#ifdef MADV_DODUMP
220 P_MADV_BHV(DODUMP);
221#endif
222#undef P_MADV_PHV
223 default: break;
224 }
225
226 return scnprintf(bf, size, "%#x", behavior);
227}
228
229#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
230
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300231static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
232 struct syscall_arg *arg)
233{
234 int printed = 0, op = arg->val;
235
236 if (op == 0)
237 return scnprintf(bf, size, "NONE");
238#define P_CMD(cmd) \
239 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
240 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
241 op &= ~LOCK_##cmd; \
242 }
243
244 P_CMD(SH);
245 P_CMD(EX);
246 P_CMD(NB);
247 P_CMD(UN);
248 P_CMD(MAND);
249 P_CMD(RW);
250 P_CMD(READ);
251 P_CMD(WRITE);
252#undef P_OP
253
254 if (op)
255 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
256
257 return printed;
258}
259
260#define SCA_FLOCK syscall_arg__scnprintf_flock
261
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300262static 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 -0300263{
264 enum syscall_futex_args {
265 SCF_UADDR = (1 << 0),
266 SCF_OP = (1 << 1),
267 SCF_VAL = (1 << 2),
268 SCF_TIMEOUT = (1 << 3),
269 SCF_UADDR2 = (1 << 4),
270 SCF_VAL3 = (1 << 5),
271 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300272 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300273 int cmd = op & FUTEX_CMD_MASK;
274 size_t printed = 0;
275
276 switch (cmd) {
277#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300278 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
279 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
280 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
281 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
282 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
283 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300284 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300285 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
286 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
287 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
288 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
289 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300290 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
291 default: printed = scnprintf(bf, size, "%#x", cmd); break;
292 }
293
294 if (op & FUTEX_PRIVATE_FLAG)
295 printed += scnprintf(bf + printed, size - printed, "|PRIV");
296
297 if (op & FUTEX_CLOCK_REALTIME)
298 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
299
300 return printed;
301}
302
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300303#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
304
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300305static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
306static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300307
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300308static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
309static DEFINE_STRARRAY(itimers);
310
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300311static const char *whences[] = { "SET", "CUR", "END",
312#ifdef SEEK_DATA
313"DATA",
314#endif
315#ifdef SEEK_HOLE
316"HOLE",
317#endif
318};
319static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300320
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300321static const char *fcntl_cmds[] = {
322 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
323 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
324 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
325 "F_GETOWNER_UIDS",
326};
327static DEFINE_STRARRAY(fcntl_cmds);
328
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300329static const char *rlimit_resources[] = {
330 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
331 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
332 "RTTIME",
333};
334static DEFINE_STRARRAY(rlimit_resources);
335
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300336static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
337static DEFINE_STRARRAY(sighow);
338
David Ahern4f8c1b72013-09-22 19:45:00 -0600339static const char *clockid[] = {
340 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
341 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
342};
343static DEFINE_STRARRAY(clockid);
344
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300345static const char *socket_families[] = {
346 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
347 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
348 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
349 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
350 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
351 "ALG", "NFC", "VSOCK",
352};
353static DEFINE_STRARRAY(socket_families);
354
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300355#ifndef SOCK_TYPE_MASK
356#define SOCK_TYPE_MASK 0xf
357#endif
358
359static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
360 struct syscall_arg *arg)
361{
362 size_t printed;
363 int type = arg->val,
364 flags = type & ~SOCK_TYPE_MASK;
365
366 type &= SOCK_TYPE_MASK;
367 /*
368 * Can't use a strarray, MIPS may override for ABI reasons.
369 */
370 switch (type) {
371#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
372 P_SK_TYPE(STREAM);
373 P_SK_TYPE(DGRAM);
374 P_SK_TYPE(RAW);
375 P_SK_TYPE(RDM);
376 P_SK_TYPE(SEQPACKET);
377 P_SK_TYPE(DCCP);
378 P_SK_TYPE(PACKET);
379#undef P_SK_TYPE
380 default:
381 printed = scnprintf(bf, size, "%#x", type);
382 }
383
384#define P_SK_FLAG(n) \
385 if (flags & SOCK_##n) { \
386 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
387 flags &= ~SOCK_##n; \
388 }
389
390 P_SK_FLAG(CLOEXEC);
391 P_SK_FLAG(NONBLOCK);
392#undef P_SK_FLAG
393
394 if (flags)
395 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
396
397 return printed;
398}
399
400#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
401
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300402#ifndef MSG_PROBE
403#define MSG_PROBE 0x10
404#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600405#ifndef MSG_WAITFORONE
406#define MSG_WAITFORONE 0x10000
407#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300408#ifndef MSG_SENDPAGE_NOTLAST
409#define MSG_SENDPAGE_NOTLAST 0x20000
410#endif
411#ifndef MSG_FASTOPEN
412#define MSG_FASTOPEN 0x20000000
413#endif
414
415static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
416 struct syscall_arg *arg)
417{
418 int printed = 0, flags = arg->val;
419
420 if (flags == 0)
421 return scnprintf(bf, size, "NONE");
422#define P_MSG_FLAG(n) \
423 if (flags & MSG_##n) { \
424 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
425 flags &= ~MSG_##n; \
426 }
427
428 P_MSG_FLAG(OOB);
429 P_MSG_FLAG(PEEK);
430 P_MSG_FLAG(DONTROUTE);
431 P_MSG_FLAG(TRYHARD);
432 P_MSG_FLAG(CTRUNC);
433 P_MSG_FLAG(PROBE);
434 P_MSG_FLAG(TRUNC);
435 P_MSG_FLAG(DONTWAIT);
436 P_MSG_FLAG(EOR);
437 P_MSG_FLAG(WAITALL);
438 P_MSG_FLAG(FIN);
439 P_MSG_FLAG(SYN);
440 P_MSG_FLAG(CONFIRM);
441 P_MSG_FLAG(RST);
442 P_MSG_FLAG(ERRQUEUE);
443 P_MSG_FLAG(NOSIGNAL);
444 P_MSG_FLAG(MORE);
445 P_MSG_FLAG(WAITFORONE);
446 P_MSG_FLAG(SENDPAGE_NOTLAST);
447 P_MSG_FLAG(FASTOPEN);
448 P_MSG_FLAG(CMSG_CLOEXEC);
449#undef P_MSG_FLAG
450
451 if (flags)
452 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
453
454 return printed;
455}
456
457#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
458
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300459static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
460 struct syscall_arg *arg)
461{
462 size_t printed = 0;
463 int mode = arg->val;
464
465 if (mode == F_OK) /* 0 */
466 return scnprintf(bf, size, "F");
467#define P_MODE(n) \
468 if (mode & n##_OK) { \
469 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
470 mode &= ~n##_OK; \
471 }
472
473 P_MODE(R);
474 P_MODE(W);
475 P_MODE(X);
476#undef P_MODE
477
478 if (mode)
479 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
480
481 return printed;
482}
483
484#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
485
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300486static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300487 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300488{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300489 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300490
491 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300492 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300493
494 if (flags == 0)
495 return scnprintf(bf, size, "RDONLY");
496#define P_FLAG(n) \
497 if (flags & O_##n) { \
498 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
499 flags &= ~O_##n; \
500 }
501
502 P_FLAG(APPEND);
503 P_FLAG(ASYNC);
504 P_FLAG(CLOEXEC);
505 P_FLAG(CREAT);
506 P_FLAG(DIRECT);
507 P_FLAG(DIRECTORY);
508 P_FLAG(EXCL);
509 P_FLAG(LARGEFILE);
510 P_FLAG(NOATIME);
511 P_FLAG(NOCTTY);
512#ifdef O_NONBLOCK
513 P_FLAG(NONBLOCK);
514#elif O_NDELAY
515 P_FLAG(NDELAY);
516#endif
517#ifdef O_PATH
518 P_FLAG(PATH);
519#endif
520 P_FLAG(RDWR);
521#ifdef O_DSYNC
522 if ((flags & O_SYNC) == O_SYNC)
523 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
524 else {
525 P_FLAG(DSYNC);
526 }
527#else
528 P_FLAG(SYNC);
529#endif
530 P_FLAG(TRUNC);
531 P_FLAG(WRONLY);
532#undef P_FLAG
533
534 if (flags)
535 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
536
537 return printed;
538}
539
540#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
541
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300542static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
543 struct syscall_arg *arg)
544{
545 int printed = 0, flags = arg->val;
546
547 if (flags == 0)
548 return scnprintf(bf, size, "NONE");
549#define P_FLAG(n) \
550 if (flags & EFD_##n) { \
551 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
552 flags &= ~EFD_##n; \
553 }
554
555 P_FLAG(SEMAPHORE);
556 P_FLAG(CLOEXEC);
557 P_FLAG(NONBLOCK);
558#undef P_FLAG
559
560 if (flags)
561 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
562
563 return printed;
564}
565
566#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
567
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300568static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
569 struct syscall_arg *arg)
570{
571 int printed = 0, flags = arg->val;
572
573#define P_FLAG(n) \
574 if (flags & O_##n) { \
575 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
576 flags &= ~O_##n; \
577 }
578
579 P_FLAG(CLOEXEC);
580 P_FLAG(NONBLOCK);
581#undef P_FLAG
582
583 if (flags)
584 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
585
586 return printed;
587}
588
589#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
590
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300591static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
592{
593 int sig = arg->val;
594
595 switch (sig) {
596#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
597 P_SIGNUM(HUP);
598 P_SIGNUM(INT);
599 P_SIGNUM(QUIT);
600 P_SIGNUM(ILL);
601 P_SIGNUM(TRAP);
602 P_SIGNUM(ABRT);
603 P_SIGNUM(BUS);
604 P_SIGNUM(FPE);
605 P_SIGNUM(KILL);
606 P_SIGNUM(USR1);
607 P_SIGNUM(SEGV);
608 P_SIGNUM(USR2);
609 P_SIGNUM(PIPE);
610 P_SIGNUM(ALRM);
611 P_SIGNUM(TERM);
612 P_SIGNUM(STKFLT);
613 P_SIGNUM(CHLD);
614 P_SIGNUM(CONT);
615 P_SIGNUM(STOP);
616 P_SIGNUM(TSTP);
617 P_SIGNUM(TTIN);
618 P_SIGNUM(TTOU);
619 P_SIGNUM(URG);
620 P_SIGNUM(XCPU);
621 P_SIGNUM(XFSZ);
622 P_SIGNUM(VTALRM);
623 P_SIGNUM(PROF);
624 P_SIGNUM(WINCH);
625 P_SIGNUM(IO);
626 P_SIGNUM(PWR);
627 P_SIGNUM(SYS);
628 default: break;
629 }
630
631 return scnprintf(bf, size, "%#x", sig);
632}
633
634#define SCA_SIGNUM syscall_arg__scnprintf_signum
635
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300636#define STRARRAY(arg, name, array) \
637 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
638 .arg_parm = { [arg] = &strarray__##array, }
639
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300640static struct syscall_fmt {
641 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300642 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300643 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300644 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300645 bool errmsg;
646 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300647 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300648} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300649 { .name = "access", .errmsg = true,
650 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300651 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300652 { .name = "brk", .hexret = true,
653 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600654 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300655 { .name = "close", .errmsg = true,
656 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300657 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300658 { .name = "dup", .errmsg = true,
659 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
660 { .name = "dup2", .errmsg = true,
661 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
662 { .name = "dup3", .errmsg = true,
663 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300664 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300665 { .name = "eventfd2", .errmsg = true,
666 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300667 { .name = "faccessat", .errmsg = true,
668 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
669 { .name = "fadvise64", .errmsg = true,
670 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
671 { .name = "fallocate", .errmsg = true,
672 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
673 { .name = "fchdir", .errmsg = true,
674 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
675 { .name = "fchmod", .errmsg = true,
676 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
677 { .name = "fchmodat", .errmsg = true,
678 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
679 { .name = "fchown", .errmsg = true,
680 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
681 { .name = "fchownat", .errmsg = true,
682 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
683 { .name = "fcntl", .errmsg = true,
684 .arg_scnprintf = { [0] = SCA_FD, /* fd */
685 [1] = SCA_STRARRAY, /* cmd */ },
686 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
687 { .name = "fdatasync", .errmsg = true,
688 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300689 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300690 .arg_scnprintf = { [0] = SCA_FD, /* fd */
691 [1] = SCA_FLOCK, /* cmd */ }, },
692 { .name = "fsetxattr", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
694 { .name = "fstat", .errmsg = true, .alias = "newfstat",
695 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
696 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
697 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
698 { .name = "fstatfs", .errmsg = true,
699 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
700 { .name = "fsync", .errmsg = true,
701 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
702 { .name = "ftruncate", .errmsg = true,
703 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300704 { .name = "futex", .errmsg = true,
705 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300706 { .name = "futimesat", .errmsg = true,
707 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
708 { .name = "getdents", .errmsg = true,
709 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
710 { .name = "getdents64", .errmsg = true,
711 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300712 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
713 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300714 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300715 .arg_scnprintf = { [0] = SCA_FD, /* fd */
716 [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300717 { .name = "kill", .errmsg = true,
718 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300719 { .name = "linkat", .errmsg = true,
720 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
721 { .name = "lseek", .errmsg = true,
722 .arg_scnprintf = { [0] = SCA_FD, /* fd */
723 [2] = SCA_STRARRAY, /* whence */ },
724 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300725 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300726 { .name = "madvise", .errmsg = true,
727 .arg_scnprintf = { [0] = SCA_HEX, /* start */
728 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300729 { .name = "mkdirat", .errmsg = true,
730 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
731 { .name = "mknodat", .errmsg = true,
732 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300733 { .name = "mlock", .errmsg = true,
734 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
735 { .name = "mlockall", .errmsg = true,
736 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300737 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300738 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300739 [2] = SCA_MMAP_PROT, /* prot */
740 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300741 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300742 .arg_scnprintf = { [0] = SCA_HEX, /* start */
743 [2] = SCA_MMAP_PROT, /* prot */ }, },
744 { .name = "mremap", .hexret = true,
745 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
746 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300747 { .name = "munlock", .errmsg = true,
748 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300749 { .name = "munmap", .errmsg = true,
750 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300751 { .name = "name_to_handle_at", .errmsg = true,
752 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
753 { .name = "newfstatat", .errmsg = true,
754 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300755 { .name = "open", .errmsg = true,
756 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300757 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300758 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
759 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300760 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300761 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
762 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300763 { .name = "pipe2", .errmsg = true,
764 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300765 { .name = "poll", .errmsg = true, .timeout = true, },
766 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300767 { .name = "pread", .errmsg = true, .alias = "pread64",
768 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
769 { .name = "preadv", .errmsg = true, .alias = "pread",
770 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300771 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300772 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
773 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
774 { .name = "pwritev", .errmsg = true,
775 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
776 { .name = "read", .errmsg = true,
777 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
778 { .name = "readlinkat", .errmsg = true,
779 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
780 { .name = "readv", .errmsg = true,
781 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300782 { .name = "recvfrom", .errmsg = true,
783 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
784 { .name = "recvmmsg", .errmsg = true,
785 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
786 { .name = "recvmsg", .errmsg = true,
787 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300788 { .name = "renameat", .errmsg = true,
789 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300790 { .name = "rt_sigaction", .errmsg = true,
791 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300792 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300793 { .name = "rt_sigqueueinfo", .errmsg = true,
794 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
795 { .name = "rt_tgsigqueueinfo", .errmsg = true,
796 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300797 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300798 { .name = "sendmmsg", .errmsg = true,
799 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
800 { .name = "sendmsg", .errmsg = true,
801 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
802 { .name = "sendto", .errmsg = true,
803 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300804 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
805 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300806 { .name = "shutdown", .errmsg = true,
807 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300808 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300809 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
810 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300811 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300812 { .name = "socketpair", .errmsg = true,
813 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
814 [1] = SCA_SK_TYPE, /* type */ },
815 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300816 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300817 { .name = "symlinkat", .errmsg = true,
818 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300819 { .name = "tgkill", .errmsg = true,
820 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
821 { .name = "tkill", .errmsg = true,
822 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300823 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300824 { .name = "unlinkat", .errmsg = true,
825 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
826 { .name = "utimensat", .errmsg = true,
827 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
828 { .name = "write", .errmsg = true,
829 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
830 { .name = "writev", .errmsg = true,
831 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300832};
833
834static int syscall_fmt__cmp(const void *name, const void *fmtp)
835{
836 const struct syscall_fmt *fmt = fmtp;
837 return strcmp(name, fmt->name);
838}
839
840static struct syscall_fmt *syscall_fmt__find(const char *name)
841{
842 const int nmemb = ARRAY_SIZE(syscall_fmts);
843 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
844}
845
846struct syscall {
847 struct event_format *tp_format;
848 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300849 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300850 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300851 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300852 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300853};
854
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200855static size_t fprintf_duration(unsigned long t, FILE *fp)
856{
857 double duration = (double)t / NSEC_PER_MSEC;
858 size_t printed = fprintf(fp, "(");
859
860 if (duration >= 1.0)
861 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
862 else if (duration >= 0.01)
863 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
864 else
865 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300866 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200867}
868
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300869struct thread_trace {
870 u64 entry_time;
871 u64 exit_time;
872 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300873 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300874 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300875 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300876 struct {
877 int max;
878 char **table;
879 } paths;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300880};
881
882static struct thread_trace *thread_trace__new(void)
883{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300884 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
885
886 if (ttrace)
887 ttrace->paths.max = -1;
888
889 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300890}
891
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300892static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300893{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300894 struct thread_trace *ttrace;
895
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300896 if (thread == NULL)
897 goto fail;
898
899 if (thread->priv == NULL)
900 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300901
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300902 if (thread->priv == NULL)
903 goto fail;
904
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300905 ttrace = thread->priv;
906 ++ttrace->nr_events;
907
908 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300909fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300910 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300911 "WARNING: not enough memory, dropping samples!\n");
912 return NULL;
913}
914
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300915struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300916 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300917 int audit_machine;
918 struct {
919 int max;
920 struct syscall *table;
921 } syscalls;
922 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -0600923 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300924 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600925 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300926 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300927 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300928 struct strlist *ev_qualifier;
929 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300930 bool live;
David Ahernbdc89662013-08-28 22:29:53 -0600931 struct intlist *tid_list;
932 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300933 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300934 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300935 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300936 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300937 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300938};
939
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300940static int thread__read_fd_path(struct thread *thread, int fd)
941{
942 struct thread_trace *ttrace = thread->priv;
943 char linkname[PATH_MAX], pathname[PATH_MAX];
944 struct stat st;
945 int ret;
946
947 if (thread->pid_ == thread->tid) {
948 scnprintf(linkname, sizeof(linkname),
949 "/proc/%d/fd/%d", thread->pid_, fd);
950 } else {
951 scnprintf(linkname, sizeof(linkname),
952 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
953 }
954
955 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
956 return -1;
957
958 ret = readlink(linkname, pathname, sizeof(pathname));
959
960 if (ret < 0 || ret > st.st_size)
961 return -1;
962
963 pathname[ret] = '\0';
964
965 if (fd > ttrace->paths.max) {
966 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
967
968 if (npath == NULL)
969 return -1;
970
971 if (ttrace->paths.max != -1) {
972 memset(npath + ttrace->paths.max + 1, 0,
973 (fd - ttrace->paths.max) * sizeof(char *));
974 } else {
975 memset(npath, 0, (fd + 1) * sizeof(char *));
976 }
977
978 ttrace->paths.table = npath;
979 ttrace->paths.max = fd;
980 }
981
982 ttrace->paths.table[fd] = strdup(pathname);
983
984 return ttrace->paths.table[fd] != NULL ? 0 : -1;
985}
986
987static const char *thread__fd_path(struct thread *thread, int fd, bool live)
988{
989 struct thread_trace *ttrace = thread->priv;
990
991 if (ttrace == NULL)
992 return NULL;
993
994 if (fd < 0)
995 return NULL;
996
997 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
998 (!live || thread__read_fd_path(thread, fd)))
999 return NULL;
1000
1001 return ttrace->paths.table[fd];
1002}
1003
1004static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1005 struct syscall_arg *arg)
1006{
1007 int fd = arg->val;
1008 size_t printed = scnprintf(bf, size, "%d", fd);
1009 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
1010
1011 if (path)
1012 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1013
1014 return printed;
1015}
1016
1017static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1018 struct syscall_arg *arg)
1019{
1020 int fd = arg->val;
1021 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1022 struct thread_trace *ttrace = arg->thread->priv;
1023
1024 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1025 free(ttrace->paths.table[fd]);
1026 ttrace->paths.table[fd] = NULL;
1027 }
1028
1029 return printed;
1030}
1031
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001032static bool trace__filter_duration(struct trace *trace, double t)
1033{
1034 return t < (trace->duration_filter * NSEC_PER_MSEC);
1035}
1036
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001037static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1038{
1039 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1040
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001041 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001042}
1043
Namhyung Kimf15eb532012-10-05 14:02:16 +09001044static bool done = false;
1045
1046static void sig_handler(int sig __maybe_unused)
1047{
1048 done = true;
1049}
1050
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001051static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001052 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001053{
1054 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001055 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001056
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001057 if (trace->multiple_threads) {
1058 if (trace->show_comm)
1059 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001060 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001061 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001062
1063 return printed;
1064}
1065
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001066static int trace__process_event(struct trace *trace, struct machine *machine,
1067 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001068{
1069 int ret = 0;
1070
1071 switch (event->header.type) {
1072 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001073 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001074 "LOST %" PRIu64 " events!\n", event->lost.lost);
1075 ret = machine__process_lost_event(machine, event);
1076 default:
1077 ret = machine__process_event(machine, event);
1078 break;
1079 }
1080
1081 return ret;
1082}
1083
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001084static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001085 union perf_event *event,
1086 struct perf_sample *sample __maybe_unused,
1087 struct machine *machine)
1088{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001089 struct trace *trace = container_of(tool, struct trace, tool);
1090 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001091}
1092
1093static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1094{
1095 int err = symbol__init();
1096
1097 if (err)
1098 return err;
1099
David Ahern8fb598e2013-09-28 13:13:00 -06001100 trace->host = machine__new_host();
1101 if (trace->host == NULL)
1102 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001103
1104 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001105 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001106 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001107 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001108 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001109 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001110 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001111 }
1112
1113 if (err)
1114 symbol__exit();
1115
1116 return err;
1117}
1118
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001119static int syscall__set_arg_fmts(struct syscall *sc)
1120{
1121 struct format_field *field;
1122 int idx = 0;
1123
1124 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1125 if (sc->arg_scnprintf == NULL)
1126 return -1;
1127
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001128 if (sc->fmt)
1129 sc->arg_parm = sc->fmt->arg_parm;
1130
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001131 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001132 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1133 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1134 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001135 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1136 ++idx;
1137 }
1138
1139 return 0;
1140}
1141
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001142static int trace__read_syscall_info(struct trace *trace, int id)
1143{
1144 char tp_name[128];
1145 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001146 const char *name = audit_syscall_to_name(id, trace->audit_machine);
1147
1148 if (name == NULL)
1149 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001150
1151 if (id > trace->syscalls.max) {
1152 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1153
1154 if (nsyscalls == NULL)
1155 return -1;
1156
1157 if (trace->syscalls.max != -1) {
1158 memset(nsyscalls + trace->syscalls.max + 1, 0,
1159 (id - trace->syscalls.max) * sizeof(*sc));
1160 } else {
1161 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1162 }
1163
1164 trace->syscalls.table = nsyscalls;
1165 trace->syscalls.max = id;
1166 }
1167
1168 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001169 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001170
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001171 if (trace->ev_qualifier) {
1172 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1173
1174 if (!(in ^ trace->not_ev_qualifier)) {
1175 sc->filtered = true;
1176 /*
1177 * No need to do read tracepoint information since this will be
1178 * filtered out.
1179 */
1180 return 0;
1181 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001182 }
1183
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001184 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001185
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001186 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1187 sc->tp_format = event_format__new("syscalls", tp_name);
1188
1189 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1190 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1191 sc->tp_format = event_format__new("syscalls", tp_name);
1192 }
1193
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001194 if (sc->tp_format == NULL)
1195 return -1;
1196
1197 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001198}
1199
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001200static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001201 unsigned long *args, struct trace *trace,
1202 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001203{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001204 size_t printed = 0;
1205
1206 if (sc->tp_format != NULL) {
1207 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001208 u8 bit = 1;
1209 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001210 .idx = 0,
1211 .mask = 0,
1212 .trace = trace,
1213 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001214 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001215
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001216 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001217 field = field->next, ++arg.idx, bit <<= 1) {
1218 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001219 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001220 /*
1221 * Suppress this argument if its value is zero and
1222 * and we don't have a string associated in an
1223 * strarray for it.
1224 */
1225 if (args[arg.idx] == 0 &&
1226 !(sc->arg_scnprintf &&
1227 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1228 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001229 continue;
1230
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001231 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001232 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001233 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1234 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001235 if (sc->arg_parm)
1236 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001237 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1238 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001239 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001240 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001241 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001242 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001243 }
1244 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001245 int i = 0;
1246
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001247 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001248 printed += scnprintf(bf + printed, size - printed,
1249 "%sarg%d: %ld",
1250 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001251 ++i;
1252 }
1253 }
1254
1255 return printed;
1256}
1257
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001258typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1259 struct perf_sample *sample);
1260
1261static struct syscall *trace__syscall_info(struct trace *trace,
1262 struct perf_evsel *evsel,
1263 struct perf_sample *sample)
1264{
1265 int id = perf_evsel__intval(evsel, sample, "id");
1266
1267 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001268
1269 /*
1270 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1271 * before that, leaving at a higher verbosity level till that is
1272 * explained. Reproduced with plain ftrace with:
1273 *
1274 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1275 * grep "NR -1 " /t/trace_pipe
1276 *
1277 * After generating some load on the machine.
1278 */
1279 if (verbose > 1) {
1280 static u64 n;
1281 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1282 id, perf_evsel__name(evsel), ++n);
1283 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001284 return NULL;
1285 }
1286
1287 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1288 trace__read_syscall_info(trace, id))
1289 goto out_cant_read;
1290
1291 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1292 goto out_cant_read;
1293
1294 return &trace->syscalls.table[id];
1295
1296out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001297 if (verbose) {
1298 fprintf(trace->output, "Problems reading syscall %d", id);
1299 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1300 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1301 fputs(" information\n", trace->output);
1302 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001303 return NULL;
1304}
1305
1306static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1307 struct perf_sample *sample)
1308{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001309 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001310 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001311 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001312 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001313 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001314 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001315
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001316 if (sc == NULL)
1317 return -1;
1318
1319 if (sc->filtered)
1320 return 0;
1321
David Ahern8fb598e2013-09-28 13:13:00 -06001322 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001323 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001324 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001325 return -1;
1326
1327 args = perf_evsel__rawptr(evsel, sample, "args");
1328 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001329 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001330 return -1;
1331 }
1332
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001333 ttrace = thread->priv;
1334
1335 if (ttrace->entry_str == NULL) {
1336 ttrace->entry_str = malloc(1024);
1337 if (!ttrace->entry_str)
1338 return -1;
1339 }
1340
1341 ttrace->entry_time = sample->time;
1342 msg = ttrace->entry_str;
1343 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1344
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001345 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1346 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001347
1348 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001349 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001350 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1351 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001352 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001353 } else
1354 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001355
1356 return 0;
1357}
1358
1359static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1360 struct perf_sample *sample)
1361{
1362 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001363 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001364 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001365 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001366 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001367
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001368 if (sc == NULL)
1369 return -1;
1370
1371 if (sc->filtered)
1372 return 0;
1373
David Ahern8fb598e2013-09-28 13:13:00 -06001374 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001375 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001376 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001377 return -1;
1378
1379 ret = perf_evsel__intval(evsel, sample, "ret");
1380
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001381 ttrace = thread->priv;
1382
1383 ttrace->exit_time = sample->time;
1384
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001385 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001386 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001387 if (trace__filter_duration(trace, duration))
1388 goto out;
1389 } else if (trace->duration_filter)
1390 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001391
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001392 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001393
1394 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001395 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001396 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001397 fprintf(trace->output, " ... [");
1398 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1399 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001400 }
1401
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001402 if (sc->fmt == NULL) {
1403signed_print:
1404 fprintf(trace->output, ") = %d", ret);
1405 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001406 char bf[256];
1407 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1408 *e = audit_errno_to_name(-ret);
1409
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001410 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001411 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001412 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001413 else if (sc->fmt->hexret)
1414 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001415 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001416 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001417
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001418 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001419out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001420 ttrace->entry_pending = false;
1421
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001422 return 0;
1423}
1424
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001425static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1426 struct perf_sample *sample)
1427{
1428 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1429 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001430 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001431 sample->pid,
1432 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001433 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001434
1435 if (ttrace == NULL)
1436 goto out_dump;
1437
1438 ttrace->runtime_ms += runtime_ms;
1439 trace->runtime_ms += runtime_ms;
1440 return 0;
1441
1442out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001443 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001444 evsel->name,
1445 perf_evsel__strval(evsel, sample, "comm"),
1446 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1447 runtime,
1448 perf_evsel__intval(evsel, sample, "vruntime"));
1449 return 0;
1450}
1451
David Ahernbdc89662013-08-28 22:29:53 -06001452static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1453{
1454 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1455 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1456 return false;
1457
1458 if (trace->pid_list || trace->tid_list)
1459 return true;
1460
1461 return false;
1462}
1463
David Ahern6810fc92013-08-28 22:29:52 -06001464static int trace__process_sample(struct perf_tool *tool,
1465 union perf_event *event __maybe_unused,
1466 struct perf_sample *sample,
1467 struct perf_evsel *evsel,
1468 struct machine *machine __maybe_unused)
1469{
1470 struct trace *trace = container_of(tool, struct trace, tool);
1471 int err = 0;
1472
1473 tracepoint_handler handler = evsel->handler.func;
1474
David Ahernbdc89662013-08-28 22:29:53 -06001475 if (skip_sample(trace, sample))
1476 return 0;
1477
David Ahern4bb09192013-09-04 12:37:43 -06001478 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001479 trace->base_time = sample->time;
1480
1481 if (handler)
1482 handler(trace, evsel, sample);
1483
1484 return err;
1485}
1486
1487static bool
1488perf_session__has_tp(struct perf_session *session, const char *name)
1489{
1490 struct perf_evsel *evsel;
1491
1492 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1493
1494 return evsel != NULL;
1495}
1496
David Ahernbdc89662013-08-28 22:29:53 -06001497static int parse_target_str(struct trace *trace)
1498{
1499 if (trace->opts.target.pid) {
1500 trace->pid_list = intlist__new(trace->opts.target.pid);
1501 if (trace->pid_list == NULL) {
1502 pr_err("Error parsing process id string\n");
1503 return -EINVAL;
1504 }
1505 }
1506
1507 if (trace->opts.target.tid) {
1508 trace->tid_list = intlist__new(trace->opts.target.tid);
1509 if (trace->tid_list == NULL) {
1510 pr_err("Error parsing thread id string\n");
1511 return -EINVAL;
1512 }
1513 }
1514
1515 return 0;
1516}
1517
David Ahern5e2485b2013-09-28 13:13:01 -06001518static int trace__record(int argc, const char **argv)
1519{
1520 unsigned int rec_argc, i, j;
1521 const char **rec_argv;
1522 const char * const record_args[] = {
1523 "record",
1524 "-R",
1525 "-m", "1024",
1526 "-c", "1",
1527 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1528 };
1529
1530 rec_argc = ARRAY_SIZE(record_args) + argc;
1531 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1532
1533 if (rec_argv == NULL)
1534 return -ENOMEM;
1535
1536 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1537 rec_argv[i] = record_args[i];
1538
1539 for (j = 0; j < (unsigned int)argc; j++, i++)
1540 rec_argv[i] = argv[j];
1541
1542 return cmd_record(i, rec_argv, NULL);
1543}
1544
Namhyung Kimf15eb532012-10-05 14:02:16 +09001545static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001546{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001547 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001548 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001549 int err = -1, i;
1550 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001551 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001552
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001553 trace->live = true;
1554
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001555 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001556 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001557 goto out;
1558 }
1559
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001560 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1561 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001562 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001563 goto out_delete_evlist;
1564 }
1565
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001566 if (trace->sched &&
1567 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1568 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001569 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001570 goto out_delete_evlist;
1571 }
1572
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001573 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1574 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001575 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001576 goto out_delete_evlist;
1577 }
1578
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001579 err = trace__symbols_init(trace, evlist);
1580 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001581 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001582 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001583 }
1584
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001585 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001586
Namhyung Kimf15eb532012-10-05 14:02:16 +09001587 signal(SIGCHLD, sig_handler);
1588 signal(SIGINT, sig_handler);
1589
1590 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001591 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001592 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001593 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001594 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001595 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001596 }
1597 }
1598
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001599 err = perf_evlist__open(evlist);
1600 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001601 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001602 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001603 }
1604
1605 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1606 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001607 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001608 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001609 }
1610
1611 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001612
1613 if (forks)
1614 perf_evlist__start_workload(evlist);
1615
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001616 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001617again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001618 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001619
1620 for (i = 0; i < evlist->nr_mmaps; i++) {
1621 union perf_event *event;
1622
1623 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1624 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001625 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001626 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001627
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001628 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001629
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001630 err = perf_evlist__parse_sample(evlist, event, &sample);
1631 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001632 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001633 continue;
1634 }
1635
David Ahern4bb09192013-09-04 12:37:43 -06001636 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001637 trace->base_time = sample.time;
1638
1639 if (type != PERF_RECORD_SAMPLE) {
David Ahern8fb598e2013-09-28 13:13:00 -06001640 trace__process_event(trace, trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001641 continue;
1642 }
1643
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001644 evsel = perf_evlist__id2evsel(evlist, sample.id);
1645 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001646 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001647 continue;
1648 }
1649
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001650 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001651 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 -03001652 perf_evsel__name(evsel), sample.tid,
1653 sample.cpu, sample.raw_size);
1654 continue;
1655 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001656
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001657 handler = evsel->handler.func;
1658 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001659
1660 if (done)
1661 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001662 }
1663 }
1664
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001665 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001666 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001667 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001668
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001669 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001670 }
1671
1672 if (done)
1673 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001674
1675 goto again;
1676
Namhyung Kim3beb0862013-03-15 14:48:50 +09001677out_unmap_evlist:
1678 perf_evlist__munmap(evlist);
1679out_close_evlist:
1680 perf_evlist__close(evlist);
1681out_delete_maps:
1682 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001683out_delete_evlist:
1684 perf_evlist__delete(evlist);
1685out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001686 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001687 return err;
1688}
1689
David Ahern6810fc92013-08-28 22:29:52 -06001690static int trace__replay(struct trace *trace)
1691{
1692 const struct perf_evsel_str_handler handlers[] = {
1693 { "raw_syscalls:sys_enter", trace__sys_enter, },
1694 { "raw_syscalls:sys_exit", trace__sys_exit, },
1695 };
1696
1697 struct perf_session *session;
1698 int err = -1;
1699
1700 trace->tool.sample = trace__process_sample;
1701 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001702 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001703 trace->tool.comm = perf_event__process_comm;
1704 trace->tool.exit = perf_event__process_exit;
1705 trace->tool.fork = perf_event__process_fork;
1706 trace->tool.attr = perf_event__process_attr;
1707 trace->tool.tracing_data = perf_event__process_tracing_data;
1708 trace->tool.build_id = perf_event__process_build_id;
1709
1710 trace->tool.ordered_samples = true;
1711 trace->tool.ordering_requires_timestamps = true;
1712
1713 /* add tid to output */
1714 trace->multiple_threads = true;
1715
1716 if (symbol__init() < 0)
1717 return -1;
1718
1719 session = perf_session__new(input_name, O_RDONLY, 0, false,
1720 &trace->tool);
1721 if (session == NULL)
1722 return -ENOMEM;
1723
David Ahern8fb598e2013-09-28 13:13:00 -06001724 trace->host = &session->machines.host;
1725
David Ahern6810fc92013-08-28 22:29:52 -06001726 err = perf_session__set_tracepoints_handlers(session, handlers);
1727 if (err)
1728 goto out;
1729
1730 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1731 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1732 goto out;
1733 }
1734
1735 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1736 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1737 goto out;
1738 }
1739
David Ahernbdc89662013-08-28 22:29:53 -06001740 err = parse_target_str(trace);
1741 if (err != 0)
1742 goto out;
1743
David Ahern6810fc92013-08-28 22:29:52 -06001744 setup_pager();
1745
1746 err = perf_session__process_events(session, &trace->tool);
1747 if (err)
1748 pr_err("Failed to process events, error %d", err);
1749
1750out:
1751 perf_session__delete(session);
1752
1753 return err;
1754}
1755
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001756static size_t trace__fprintf_threads_header(FILE *fp)
1757{
1758 size_t printed;
1759
1760 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1761 printed += fprintf(fp," __) Summary of events (__\n\n");
1762 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1763 printed += fprintf(fp," _____________________________________________________________________\n\n");
1764
1765 return printed;
1766}
1767
David Ahern896cbb52013-09-28 13:12:59 -06001768/* struct used to pass data to per-thread function */
1769struct summary_data {
1770 FILE *fp;
1771 struct trace *trace;
1772 size_t printed;
1773};
1774
1775static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1776{
1777 struct summary_data *data = priv;
1778 FILE *fp = data->fp;
1779 size_t printed = data->printed;
1780 struct trace *trace = data->trace;
1781 struct thread_trace *ttrace = thread->priv;
1782 const char *color;
1783 double ratio;
1784
1785 if (ttrace == NULL)
1786 return 0;
1787
1788 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1789
1790 color = PERF_COLOR_NORMAL;
1791 if (ratio > 50.0)
1792 color = PERF_COLOR_RED;
1793 else if (ratio > 25.0)
1794 color = PERF_COLOR_GREEN;
1795 else if (ratio > 5.0)
1796 color = PERF_COLOR_YELLOW;
1797
1798 printed += color_fprintf(fp, color, "%20s", thread->comm);
1799 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1800 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1801 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1802
1803 data->printed += printed;
1804
1805 return 0;
1806}
1807
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001808static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1809{
David Ahern896cbb52013-09-28 13:12:59 -06001810 struct summary_data data = {
1811 .fp = fp,
1812 .trace = trace
1813 };
1814 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001815
David Ahern896cbb52013-09-28 13:12:59 -06001816 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001817
David Ahern896cbb52013-09-28 13:12:59 -06001818 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001819}
1820
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001821static int trace__set_duration(const struct option *opt, const char *str,
1822 int unset __maybe_unused)
1823{
1824 struct trace *trace = opt->value;
1825
1826 trace->duration_filter = atof(str);
1827 return 0;
1828}
1829
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001830static int trace__open_output(struct trace *trace, const char *filename)
1831{
1832 struct stat st;
1833
1834 if (!stat(filename, &st) && st.st_size) {
1835 char oldname[PATH_MAX];
1836
1837 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1838 unlink(oldname);
1839 rename(filename, oldname);
1840 }
1841
1842 trace->output = fopen(filename, "w");
1843
1844 return trace->output == NULL ? -errno : 0;
1845}
1846
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001847int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1848{
1849 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001850 "perf trace [<options>] [<command>]",
1851 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06001852 "perf trace record [<options>] [<command>]",
1853 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001854 NULL
1855 };
1856 struct trace trace = {
1857 .audit_machine = audit_detect_machine(),
1858 .syscalls = {
1859 . max = -1,
1860 },
1861 .opts = {
1862 .target = {
1863 .uid = UINT_MAX,
1864 .uses_mmap = true,
1865 },
1866 .user_freq = UINT_MAX,
1867 .user_interval = ULLONG_MAX,
1868 .no_delay = true,
1869 .mmap_pages = 1024,
1870 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001871 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001872 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001873 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001874 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001875 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001876 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001877 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1878 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001879 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1880 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001881 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001882 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001883 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1884 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001885 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001886 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001887 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001888 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001889 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001890 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001891 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001892 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001893 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1894 "number of mmap data pages",
1895 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001896 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001897 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001898 OPT_CALLBACK(0, "duration", &trace, "float",
1899 "show only events with duration > N.M ms",
1900 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001901 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001902 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001903 OPT_BOOLEAN('T', "time", &trace.full_time,
1904 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001905 OPT_END()
1906 };
1907 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001908 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001909
David Ahern5e2485b2013-09-28 13:13:01 -06001910 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
1911 return trace__record(argc-2, &argv[2]);
1912
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001913 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001914
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001915 if (output_name != NULL) {
1916 err = trace__open_output(&trace, output_name);
1917 if (err < 0) {
1918 perror("failed to create output file");
1919 goto out;
1920 }
1921 }
1922
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001923 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001924 const char *s = ev_qualifier_str;
1925
1926 trace.not_ev_qualifier = *s == '!';
1927 if (trace.not_ev_qualifier)
1928 ++s;
1929 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001930 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001931 fputs("Not enough memory to parse event qualifier",
1932 trace.output);
1933 err = -ENOMEM;
1934 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001935 }
1936 }
1937
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001938 err = perf_target__validate(&trace.opts.target);
1939 if (err) {
1940 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001941 fprintf(trace.output, "%s", bf);
1942 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001943 }
1944
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001945 err = perf_target__parse_uid(&trace.opts.target);
1946 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001947 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001948 fprintf(trace.output, "%s", bf);
1949 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001950 }
1951
Namhyung Kimf15eb532012-10-05 14:02:16 +09001952 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001953 trace.opts.target.system_wide = true;
1954
David Ahern6810fc92013-08-28 22:29:52 -06001955 if (input_name)
1956 err = trace__replay(&trace);
1957 else
1958 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001959
1960 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001961 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001962
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001963out_close:
1964 if (output_name != NULL)
1965 fclose(trace.output);
1966out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001967 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001968}