blob: 19ddcabc73d2bbdc68eed782711eb99098120258 [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 Melo78645cf2013-10-08 17:43:20 -030084static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size,
85 struct syscall_arg *arg)
86{
87 return __syscall_arg__scnprintf_strarray(bf, size, "%#x", arg);
88}
89
90#define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray
91
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -030092static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
93 struct syscall_arg *arg);
94
95#define SCA_FD syscall_arg__scnprintf_fd
96
97static size_t syscall_arg__scnprintf_fd_at(char *bf, size_t size,
98 struct syscall_arg *arg)
99{
100 int fd = arg->val;
101
102 if (fd == AT_FDCWD)
103 return scnprintf(bf, size, "CWD");
104
105 return syscall_arg__scnprintf_fd(bf, size, arg);
106}
107
108#define SCA_FDAT syscall_arg__scnprintf_fd_at
109
110static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
111 struct syscall_arg *arg);
112
113#define SCA_CLOSE_FD syscall_arg__scnprintf_close_fd
114
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300115static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300116 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300117{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300118 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300119}
120
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300121#define SCA_HEX syscall_arg__scnprintf_hex
122
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300123static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300124 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300125{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300126 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300127
128 if (prot == PROT_NONE)
129 return scnprintf(bf, size, "NONE");
130#define P_MMAP_PROT(n) \
131 if (prot & PROT_##n) { \
132 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
133 prot &= ~PROT_##n; \
134 }
135
136 P_MMAP_PROT(EXEC);
137 P_MMAP_PROT(READ);
138 P_MMAP_PROT(WRITE);
139#ifdef PROT_SEM
140 P_MMAP_PROT(SEM);
141#endif
142 P_MMAP_PROT(GROWSDOWN);
143 P_MMAP_PROT(GROWSUP);
144#undef P_MMAP_PROT
145
146 if (prot)
147 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
148
149 return printed;
150}
151
152#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
153
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300154static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300155 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300156{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300157 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300158
159#define P_MMAP_FLAG(n) \
160 if (flags & MAP_##n) { \
161 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
162 flags &= ~MAP_##n; \
163 }
164
165 P_MMAP_FLAG(SHARED);
166 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400167#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300168 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400169#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300170 P_MMAP_FLAG(ANONYMOUS);
171 P_MMAP_FLAG(DENYWRITE);
172 P_MMAP_FLAG(EXECUTABLE);
173 P_MMAP_FLAG(FILE);
174 P_MMAP_FLAG(FIXED);
175 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600176#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300177 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600178#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300179 P_MMAP_FLAG(LOCKED);
180 P_MMAP_FLAG(NONBLOCK);
181 P_MMAP_FLAG(NORESERVE);
182 P_MMAP_FLAG(POPULATE);
183 P_MMAP_FLAG(STACK);
184#ifdef MAP_UNINITIALIZED
185 P_MMAP_FLAG(UNINITIALIZED);
186#endif
187#undef P_MMAP_FLAG
188
189 if (flags)
190 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
191
192 return printed;
193}
194
195#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
196
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300197static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300198 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300199{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300200 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300201
202 switch (behavior) {
203#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
204 P_MADV_BHV(NORMAL);
205 P_MADV_BHV(RANDOM);
206 P_MADV_BHV(SEQUENTIAL);
207 P_MADV_BHV(WILLNEED);
208 P_MADV_BHV(DONTNEED);
209 P_MADV_BHV(REMOVE);
210 P_MADV_BHV(DONTFORK);
211 P_MADV_BHV(DOFORK);
212 P_MADV_BHV(HWPOISON);
213#ifdef MADV_SOFT_OFFLINE
214 P_MADV_BHV(SOFT_OFFLINE);
215#endif
216 P_MADV_BHV(MERGEABLE);
217 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600218#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300219 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600220#endif
221#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300222 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600223#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300224#ifdef MADV_DONTDUMP
225 P_MADV_BHV(DONTDUMP);
226#endif
227#ifdef MADV_DODUMP
228 P_MADV_BHV(DODUMP);
229#endif
230#undef P_MADV_PHV
231 default: break;
232 }
233
234 return scnprintf(bf, size, "%#x", behavior);
235}
236
237#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
238
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300239static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
240 struct syscall_arg *arg)
241{
242 int printed = 0, op = arg->val;
243
244 if (op == 0)
245 return scnprintf(bf, size, "NONE");
246#define P_CMD(cmd) \
247 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
248 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
249 op &= ~LOCK_##cmd; \
250 }
251
252 P_CMD(SH);
253 P_CMD(EX);
254 P_CMD(NB);
255 P_CMD(UN);
256 P_CMD(MAND);
257 P_CMD(RW);
258 P_CMD(READ);
259 P_CMD(WRITE);
260#undef P_OP
261
262 if (op)
263 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
264
265 return printed;
266}
267
268#define SCA_FLOCK syscall_arg__scnprintf_flock
269
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300270static 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 -0300271{
272 enum syscall_futex_args {
273 SCF_UADDR = (1 << 0),
274 SCF_OP = (1 << 1),
275 SCF_VAL = (1 << 2),
276 SCF_TIMEOUT = (1 << 3),
277 SCF_UADDR2 = (1 << 4),
278 SCF_VAL3 = (1 << 5),
279 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300280 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300281 int cmd = op & FUTEX_CMD_MASK;
282 size_t printed = 0;
283
284 switch (cmd) {
285#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300286 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
287 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
288 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
289 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
290 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
291 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300292 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300293 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
294 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
295 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
296 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
297 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300298 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
299 default: printed = scnprintf(bf, size, "%#x", cmd); break;
300 }
301
302 if (op & FUTEX_PRIVATE_FLAG)
303 printed += scnprintf(bf + printed, size - printed, "|PRIV");
304
305 if (op & FUTEX_CLOCK_REALTIME)
306 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
307
308 return printed;
309}
310
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300311#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
312
Arnaldo Carvalho de Melo03e3adc2013-10-08 16:00:21 -0300313static const char *epoll_ctl_ops[] = { "ADD", "DEL", "MOD", };
314static DEFINE_STRARRAY_OFFSET(epoll_ctl_ops, 1);
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300315
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300316static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
317static DEFINE_STRARRAY(itimers);
318
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300319static const char *whences[] = { "SET", "CUR", "END",
320#ifdef SEEK_DATA
321"DATA",
322#endif
323#ifdef SEEK_HOLE
324"HOLE",
325#endif
326};
327static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300328
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300329static const char *fcntl_cmds[] = {
330 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
331 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
332 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
333 "F_GETOWNER_UIDS",
334};
335static DEFINE_STRARRAY(fcntl_cmds);
336
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300337static const char *rlimit_resources[] = {
338 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
339 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
340 "RTTIME",
341};
342static DEFINE_STRARRAY(rlimit_resources);
343
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300344static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
345static DEFINE_STRARRAY(sighow);
346
David Ahern4f8c1b72013-09-22 19:45:00 -0600347static const char *clockid[] = {
348 "REALTIME", "MONOTONIC", "PROCESS_CPUTIME_ID", "THREAD_CPUTIME_ID",
349 "MONOTONIC_RAW", "REALTIME_COARSE", "MONOTONIC_COARSE",
350};
351static DEFINE_STRARRAY(clockid);
352
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300353static const char *socket_families[] = {
354 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
355 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
356 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
357 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
358 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
359 "ALG", "NFC", "VSOCK",
360};
361static DEFINE_STRARRAY(socket_families);
362
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300363#ifndef SOCK_TYPE_MASK
364#define SOCK_TYPE_MASK 0xf
365#endif
366
367static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
368 struct syscall_arg *arg)
369{
370 size_t printed;
371 int type = arg->val,
372 flags = type & ~SOCK_TYPE_MASK;
373
374 type &= SOCK_TYPE_MASK;
375 /*
376 * Can't use a strarray, MIPS may override for ABI reasons.
377 */
378 switch (type) {
379#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
380 P_SK_TYPE(STREAM);
381 P_SK_TYPE(DGRAM);
382 P_SK_TYPE(RAW);
383 P_SK_TYPE(RDM);
384 P_SK_TYPE(SEQPACKET);
385 P_SK_TYPE(DCCP);
386 P_SK_TYPE(PACKET);
387#undef P_SK_TYPE
388 default:
389 printed = scnprintf(bf, size, "%#x", type);
390 }
391
392#define P_SK_FLAG(n) \
393 if (flags & SOCK_##n) { \
394 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
395 flags &= ~SOCK_##n; \
396 }
397
398 P_SK_FLAG(CLOEXEC);
399 P_SK_FLAG(NONBLOCK);
400#undef P_SK_FLAG
401
402 if (flags)
403 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
404
405 return printed;
406}
407
408#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
409
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300410#ifndef MSG_PROBE
411#define MSG_PROBE 0x10
412#endif
David Ahernb6e8f8f2013-09-22 19:44:56 -0600413#ifndef MSG_WAITFORONE
414#define MSG_WAITFORONE 0x10000
415#endif
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300416#ifndef MSG_SENDPAGE_NOTLAST
417#define MSG_SENDPAGE_NOTLAST 0x20000
418#endif
419#ifndef MSG_FASTOPEN
420#define MSG_FASTOPEN 0x20000000
421#endif
422
423static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
424 struct syscall_arg *arg)
425{
426 int printed = 0, flags = arg->val;
427
428 if (flags == 0)
429 return scnprintf(bf, size, "NONE");
430#define P_MSG_FLAG(n) \
431 if (flags & MSG_##n) { \
432 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
433 flags &= ~MSG_##n; \
434 }
435
436 P_MSG_FLAG(OOB);
437 P_MSG_FLAG(PEEK);
438 P_MSG_FLAG(DONTROUTE);
439 P_MSG_FLAG(TRYHARD);
440 P_MSG_FLAG(CTRUNC);
441 P_MSG_FLAG(PROBE);
442 P_MSG_FLAG(TRUNC);
443 P_MSG_FLAG(DONTWAIT);
444 P_MSG_FLAG(EOR);
445 P_MSG_FLAG(WAITALL);
446 P_MSG_FLAG(FIN);
447 P_MSG_FLAG(SYN);
448 P_MSG_FLAG(CONFIRM);
449 P_MSG_FLAG(RST);
450 P_MSG_FLAG(ERRQUEUE);
451 P_MSG_FLAG(NOSIGNAL);
452 P_MSG_FLAG(MORE);
453 P_MSG_FLAG(WAITFORONE);
454 P_MSG_FLAG(SENDPAGE_NOTLAST);
455 P_MSG_FLAG(FASTOPEN);
456 P_MSG_FLAG(CMSG_CLOEXEC);
457#undef P_MSG_FLAG
458
459 if (flags)
460 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
461
462 return printed;
463}
464
465#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
466
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300467static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
468 struct syscall_arg *arg)
469{
470 size_t printed = 0;
471 int mode = arg->val;
472
473 if (mode == F_OK) /* 0 */
474 return scnprintf(bf, size, "F");
475#define P_MODE(n) \
476 if (mode & n##_OK) { \
477 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
478 mode &= ~n##_OK; \
479 }
480
481 P_MODE(R);
482 P_MODE(W);
483 P_MODE(X);
484#undef P_MODE
485
486 if (mode)
487 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
488
489 return printed;
490}
491
492#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
493
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300494static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300495 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300496{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300497 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300498
499 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300500 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300501
502 if (flags == 0)
503 return scnprintf(bf, size, "RDONLY");
504#define P_FLAG(n) \
505 if (flags & O_##n) { \
506 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
507 flags &= ~O_##n; \
508 }
509
510 P_FLAG(APPEND);
511 P_FLAG(ASYNC);
512 P_FLAG(CLOEXEC);
513 P_FLAG(CREAT);
514 P_FLAG(DIRECT);
515 P_FLAG(DIRECTORY);
516 P_FLAG(EXCL);
517 P_FLAG(LARGEFILE);
518 P_FLAG(NOATIME);
519 P_FLAG(NOCTTY);
520#ifdef O_NONBLOCK
521 P_FLAG(NONBLOCK);
522#elif O_NDELAY
523 P_FLAG(NDELAY);
524#endif
525#ifdef O_PATH
526 P_FLAG(PATH);
527#endif
528 P_FLAG(RDWR);
529#ifdef O_DSYNC
530 if ((flags & O_SYNC) == O_SYNC)
531 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
532 else {
533 P_FLAG(DSYNC);
534 }
535#else
536 P_FLAG(SYNC);
537#endif
538 P_FLAG(TRUNC);
539 P_FLAG(WRONLY);
540#undef P_FLAG
541
542 if (flags)
543 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
544
545 return printed;
546}
547
548#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
549
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300550static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
551 struct syscall_arg *arg)
552{
553 int printed = 0, flags = arg->val;
554
555 if (flags == 0)
556 return scnprintf(bf, size, "NONE");
557#define P_FLAG(n) \
558 if (flags & EFD_##n) { \
559 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
560 flags &= ~EFD_##n; \
561 }
562
563 P_FLAG(SEMAPHORE);
564 P_FLAG(CLOEXEC);
565 P_FLAG(NONBLOCK);
566#undef P_FLAG
567
568 if (flags)
569 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
570
571 return printed;
572}
573
574#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
575
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300576static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
577 struct syscall_arg *arg)
578{
579 int printed = 0, flags = arg->val;
580
581#define P_FLAG(n) \
582 if (flags & O_##n) { \
583 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
584 flags &= ~O_##n; \
585 }
586
587 P_FLAG(CLOEXEC);
588 P_FLAG(NONBLOCK);
589#undef P_FLAG
590
591 if (flags)
592 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
593
594 return printed;
595}
596
597#define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags
598
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300599static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
600{
601 int sig = arg->val;
602
603 switch (sig) {
604#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
605 P_SIGNUM(HUP);
606 P_SIGNUM(INT);
607 P_SIGNUM(QUIT);
608 P_SIGNUM(ILL);
609 P_SIGNUM(TRAP);
610 P_SIGNUM(ABRT);
611 P_SIGNUM(BUS);
612 P_SIGNUM(FPE);
613 P_SIGNUM(KILL);
614 P_SIGNUM(USR1);
615 P_SIGNUM(SEGV);
616 P_SIGNUM(USR2);
617 P_SIGNUM(PIPE);
618 P_SIGNUM(ALRM);
619 P_SIGNUM(TERM);
620 P_SIGNUM(STKFLT);
621 P_SIGNUM(CHLD);
622 P_SIGNUM(CONT);
623 P_SIGNUM(STOP);
624 P_SIGNUM(TSTP);
625 P_SIGNUM(TTIN);
626 P_SIGNUM(TTOU);
627 P_SIGNUM(URG);
628 P_SIGNUM(XCPU);
629 P_SIGNUM(XFSZ);
630 P_SIGNUM(VTALRM);
631 P_SIGNUM(PROF);
632 P_SIGNUM(WINCH);
633 P_SIGNUM(IO);
634 P_SIGNUM(PWR);
635 P_SIGNUM(SYS);
636 default: break;
637 }
638
639 return scnprintf(bf, size, "%#x", sig);
640}
641
642#define SCA_SIGNUM syscall_arg__scnprintf_signum
643
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300644#define TCGETS 0x5401
645
646static const char *tioctls[] = {
647 "TCGETS", "TCSETS", "TCSETSW", "TCSETSF", "TCGETA", "TCSETA", "TCSETAW",
648 "TCSETAF", "TCSBRK", "TCXONC", "TCFLSH", "TIOCEXCL", "TIOCNXCL",
649 "TIOCSCTTY", "TIOCGPGRP", "TIOCSPGRP", "TIOCOUTQ", "TIOCSTI",
650 "TIOCGWINSZ", "TIOCSWINSZ", "TIOCMGET", "TIOCMBIS", "TIOCMBIC",
651 "TIOCMSET", "TIOCGSOFTCAR", "TIOCSSOFTCAR", "FIONREAD", "TIOCLINUX",
652 "TIOCCONS", "TIOCGSERIAL", "TIOCSSERIAL", "TIOCPKT", "FIONBIO",
653 "TIOCNOTTY", "TIOCSETD", "TIOCGETD", "TCSBRKP", [0x27] = "TIOCSBRK",
654 "TIOCCBRK", "TIOCGSID", "TCGETS2", "TCSETS2", "TCSETSW2", "TCSETSF2",
655 "TIOCGRS485", "TIOCSRS485", "TIOCGPTN", "TIOCSPTLCK",
656 "TIOCGDEV||TCGETX", "TCSETX", "TCSETXF", "TCSETXW", "TIOCSIG",
657 "TIOCVHANGUP", "TIOCGPKT", "TIOCGPTLCK", "TIOCGEXCL",
658 [0x50] = "FIONCLEX", "FIOCLEX", "FIOASYNC", "TIOCSERCONFIG",
659 "TIOCSERGWILD", "TIOCSERSWILD", "TIOCGLCKTRMIOS", "TIOCSLCKTRMIOS",
660 "TIOCSERGSTRUCT", "TIOCSERGETLSR", "TIOCSERGETMULTI", "TIOCSERSETMULTI",
661 "TIOCMIWAIT", "TIOCGICOUNT", [0x60] = "FIOQSIZE",
662};
663
664static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
665
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300666#define STRARRAY(arg, name, array) \
667 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
668 .arg_parm = { [arg] = &strarray__##array, }
669
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300670static struct syscall_fmt {
671 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300672 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300673 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300674 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300675 bool errmsg;
676 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300677 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300678} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300679 { .name = "access", .errmsg = true,
680 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300681 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300682 { .name = "brk", .hexret = true,
683 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
David Ahern4f8c1b72013-09-22 19:45:00 -0600684 { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300685 { .name = "close", .errmsg = true,
686 .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300687 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300688 { .name = "dup", .errmsg = true,
689 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
690 { .name = "dup2", .errmsg = true,
691 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
692 { .name = "dup3", .errmsg = true,
693 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300694 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300695 { .name = "eventfd2", .errmsg = true,
696 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300697 { .name = "faccessat", .errmsg = true,
698 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
699 { .name = "fadvise64", .errmsg = true,
700 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
701 { .name = "fallocate", .errmsg = true,
702 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
703 { .name = "fchdir", .errmsg = true,
704 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
705 { .name = "fchmod", .errmsg = true,
706 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
707 { .name = "fchmodat", .errmsg = true,
708 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
709 { .name = "fchown", .errmsg = true,
710 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
711 { .name = "fchownat", .errmsg = true,
712 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
713 { .name = "fcntl", .errmsg = true,
714 .arg_scnprintf = { [0] = SCA_FD, /* fd */
715 [1] = SCA_STRARRAY, /* cmd */ },
716 .arg_parm = { [1] = &strarray__fcntl_cmds, /* cmd */ }, },
717 { .name = "fdatasync", .errmsg = true,
718 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300719 { .name = "flock", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300720 .arg_scnprintf = { [0] = SCA_FD, /* fd */
721 [1] = SCA_FLOCK, /* cmd */ }, },
722 { .name = "fsetxattr", .errmsg = true,
723 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
724 { .name = "fstat", .errmsg = true, .alias = "newfstat",
725 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
726 { .name = "fstatat", .errmsg = true, .alias = "newfstatat",
727 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
728 { .name = "fstatfs", .errmsg = true,
729 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
730 { .name = "fsync", .errmsg = true,
731 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
732 { .name = "ftruncate", .errmsg = true,
733 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300734 { .name = "futex", .errmsg = true,
735 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300736 { .name = "futimesat", .errmsg = true,
737 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
738 { .name = "getdents", .errmsg = true,
739 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
740 { .name = "getdents64", .errmsg = true,
741 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300742 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
743 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300744 { .name = "ioctl", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300745 .arg_scnprintf = { [0] = SCA_FD, /* fd */
Arnaldo Carvalho de Melo78645cf2013-10-08 17:43:20 -0300746 [1] = SCA_STRHEXARRAY, /* cmd */
747 [2] = SCA_HEX, /* arg */ },
748 .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300749 { .name = "kill", .errmsg = true,
750 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300751 { .name = "linkat", .errmsg = true,
752 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
753 { .name = "lseek", .errmsg = true,
754 .arg_scnprintf = { [0] = SCA_FD, /* fd */
755 [2] = SCA_STRARRAY, /* whence */ },
756 .arg_parm = { [2] = &strarray__whences, /* whence */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300757 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300758 { .name = "madvise", .errmsg = true,
759 .arg_scnprintf = { [0] = SCA_HEX, /* start */
760 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300761 { .name = "mkdirat", .errmsg = true,
762 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
763 { .name = "mknodat", .errmsg = true,
764 .arg_scnprintf = { [0] = SCA_FDAT, /* fd */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300765 { .name = "mlock", .errmsg = true,
766 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
767 { .name = "mlockall", .errmsg = true,
768 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300769 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300770 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300771 [2] = SCA_MMAP_PROT, /* prot */
772 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300773 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300774 .arg_scnprintf = { [0] = SCA_HEX, /* start */
775 [2] = SCA_MMAP_PROT, /* prot */ }, },
776 { .name = "mremap", .hexret = true,
777 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
778 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melo3d903aa2013-09-24 00:09:38 -0300779 { .name = "munlock", .errmsg = true,
780 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300781 { .name = "munmap", .errmsg = true,
782 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300783 { .name = "name_to_handle_at", .errmsg = true,
784 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
785 { .name = "newfstatat", .errmsg = true,
786 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300787 { .name = "open", .errmsg = true,
788 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300789 { .name = "open_by_handle_at", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300790 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
791 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300792 { .name = "openat", .errmsg = true,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300793 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */
794 [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo46cce192013-09-23 12:52:04 -0300795 { .name = "pipe2", .errmsg = true,
796 .arg_scnprintf = { [1] = SCA_PIPE_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300797 { .name = "poll", .errmsg = true, .timeout = true, },
798 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300799 { .name = "pread", .errmsg = true, .alias = "pread64",
800 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
801 { .name = "preadv", .errmsg = true, .alias = "pread",
802 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300803 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300804 { .name = "pwrite", .errmsg = true, .alias = "pwrite64",
805 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
806 { .name = "pwritev", .errmsg = true,
807 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
808 { .name = "read", .errmsg = true,
809 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
810 { .name = "readlinkat", .errmsg = true,
811 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
812 { .name = "readv", .errmsg = true,
813 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300814 { .name = "recvfrom", .errmsg = true,
815 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
816 { .name = "recvmmsg", .errmsg = true,
817 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
818 { .name = "recvmsg", .errmsg = true,
819 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300820 { .name = "renameat", .errmsg = true,
821 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300822 { .name = "rt_sigaction", .errmsg = true,
823 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300824 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300825 { .name = "rt_sigqueueinfo", .errmsg = true,
826 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
827 { .name = "rt_tgsigqueueinfo", .errmsg = true,
828 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300829 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300830 { .name = "sendmmsg", .errmsg = true,
831 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
832 { .name = "sendmsg", .errmsg = true,
833 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
834 { .name = "sendto", .errmsg = true,
835 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300836 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
837 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300838 { .name = "shutdown", .errmsg = true,
839 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300840 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300841 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
842 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300843 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300844 { .name = "socketpair", .errmsg = true,
845 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
846 [1] = SCA_SK_TYPE, /* type */ },
847 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300848 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300849 { .name = "symlinkat", .errmsg = true,
850 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300851 { .name = "tgkill", .errmsg = true,
852 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
853 { .name = "tkill", .errmsg = true,
854 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300855 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300856 { .name = "unlinkat", .errmsg = true,
857 .arg_scnprintf = { [0] = SCA_FDAT, /* dfd */ }, },
858 { .name = "utimensat", .errmsg = true,
859 .arg_scnprintf = { [0] = SCA_FDAT, /* dirfd */ }, },
860 { .name = "write", .errmsg = true,
861 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
862 { .name = "writev", .errmsg = true,
863 .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300864};
865
866static int syscall_fmt__cmp(const void *name, const void *fmtp)
867{
868 const struct syscall_fmt *fmt = fmtp;
869 return strcmp(name, fmt->name);
870}
871
872static struct syscall_fmt *syscall_fmt__find(const char *name)
873{
874 const int nmemb = ARRAY_SIZE(syscall_fmts);
875 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
876}
877
878struct syscall {
879 struct event_format *tp_format;
880 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300881 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300882 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300883 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300884 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300885};
886
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200887static size_t fprintf_duration(unsigned long t, FILE *fp)
888{
889 double duration = (double)t / NSEC_PER_MSEC;
890 size_t printed = fprintf(fp, "(");
891
892 if (duration >= 1.0)
893 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
894 else if (duration >= 0.01)
895 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
896 else
897 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300898 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200899}
900
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300901struct thread_trace {
902 u64 entry_time;
903 u64 exit_time;
904 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300905 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300906 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300907 double runtime_ms;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300908 struct {
909 int max;
910 char **table;
911 } paths;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300912};
913
914static struct thread_trace *thread_trace__new(void)
915{
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300916 struct thread_trace *ttrace = zalloc(sizeof(struct thread_trace));
917
918 if (ttrace)
919 ttrace->paths.max = -1;
920
921 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300922}
923
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300924static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300925{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300926 struct thread_trace *ttrace;
927
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300928 if (thread == NULL)
929 goto fail;
930
931 if (thread->priv == NULL)
932 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300933
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300934 if (thread->priv == NULL)
935 goto fail;
936
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300937 ttrace = thread->priv;
938 ++ttrace->nr_events;
939
940 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300941fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300942 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300943 "WARNING: not enough memory, dropping samples!\n");
944 return NULL;
945}
946
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300947struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300948 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300949 int audit_machine;
950 struct {
951 int max;
952 struct syscall *table;
953 } syscalls;
954 struct perf_record_opts opts;
David Ahern8fb598e2013-09-28 13:13:00 -0600955 struct machine *host;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300956 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600957 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300958 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300959 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300960 struct strlist *ev_qualifier;
961 bool not_ev_qualifier;
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300962 bool live;
David Ahernbdc89662013-08-28 22:29:53 -0600963 struct intlist *tid_list;
964 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300965 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300966 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300967 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300968 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300969 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300970};
971
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -0300972static int thread__read_fd_path(struct thread *thread, int fd)
973{
974 struct thread_trace *ttrace = thread->priv;
975 char linkname[PATH_MAX], pathname[PATH_MAX];
976 struct stat st;
977 int ret;
978
979 if (thread->pid_ == thread->tid) {
980 scnprintf(linkname, sizeof(linkname),
981 "/proc/%d/fd/%d", thread->pid_, fd);
982 } else {
983 scnprintf(linkname, sizeof(linkname),
984 "/proc/%d/task/%d/fd/%d", thread->pid_, thread->tid, fd);
985 }
986
987 if (lstat(linkname, &st) < 0 || st.st_size + 1 > (off_t)sizeof(pathname))
988 return -1;
989
990 ret = readlink(linkname, pathname, sizeof(pathname));
991
992 if (ret < 0 || ret > st.st_size)
993 return -1;
994
995 pathname[ret] = '\0';
996
997 if (fd > ttrace->paths.max) {
998 char **npath = realloc(ttrace->paths.table, (fd + 1) * sizeof(char *));
999
1000 if (npath == NULL)
1001 return -1;
1002
1003 if (ttrace->paths.max != -1) {
1004 memset(npath + ttrace->paths.max + 1, 0,
1005 (fd - ttrace->paths.max) * sizeof(char *));
1006 } else {
1007 memset(npath, 0, (fd + 1) * sizeof(char *));
1008 }
1009
1010 ttrace->paths.table = npath;
1011 ttrace->paths.max = fd;
1012 }
1013
1014 ttrace->paths.table[fd] = strdup(pathname);
1015
1016 return ttrace->paths.table[fd] != NULL ? 0 : -1;
1017}
1018
1019static const char *thread__fd_path(struct thread *thread, int fd, bool live)
1020{
1021 struct thread_trace *ttrace = thread->priv;
1022
1023 if (ttrace == NULL)
1024 return NULL;
1025
1026 if (fd < 0)
1027 return NULL;
1028
1029 if ((fd > ttrace->paths.max || ttrace->paths.table[fd] == NULL) &&
1030 (!live || thread__read_fd_path(thread, fd)))
1031 return NULL;
1032
1033 return ttrace->paths.table[fd];
1034}
1035
1036static size_t syscall_arg__scnprintf_fd(char *bf, size_t size,
1037 struct syscall_arg *arg)
1038{
1039 int fd = arg->val;
1040 size_t printed = scnprintf(bf, size, "%d", fd);
1041 const char *path = thread__fd_path(arg->thread, fd, arg->trace->live);
1042
1043 if (path)
1044 printed += scnprintf(bf + printed, size - printed, "<%s>", path);
1045
1046 return printed;
1047}
1048
1049static size_t syscall_arg__scnprintf_close_fd(char *bf, size_t size,
1050 struct syscall_arg *arg)
1051{
1052 int fd = arg->val;
1053 size_t printed = syscall_arg__scnprintf_fd(bf, size, arg);
1054 struct thread_trace *ttrace = arg->thread->priv;
1055
1056 if (ttrace && fd >= 0 && fd <= ttrace->paths.max) {
1057 free(ttrace->paths.table[fd]);
1058 ttrace->paths.table[fd] = NULL;
1059 }
1060
1061 return printed;
1062}
1063
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001064static bool trace__filter_duration(struct trace *trace, double t)
1065{
1066 return t < (trace->duration_filter * NSEC_PER_MSEC);
1067}
1068
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001069static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
1070{
1071 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
1072
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001073 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001074}
1075
Namhyung Kimf15eb532012-10-05 14:02:16 +09001076static bool done = false;
1077
1078static void sig_handler(int sig __maybe_unused)
1079{
1080 done = true;
1081}
1082
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001083static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001084 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001085{
1086 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001087 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001088
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001089 if (trace->multiple_threads) {
1090 if (trace->show_comm)
1091 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001092 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001093 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001094
1095 return printed;
1096}
1097
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001098static int trace__process_event(struct trace *trace, struct machine *machine,
1099 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001100{
1101 int ret = 0;
1102
1103 switch (event->header.type) {
1104 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001105 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001106 "LOST %" PRIu64 " events!\n", event->lost.lost);
1107 ret = machine__process_lost_event(machine, event);
1108 default:
1109 ret = machine__process_event(machine, event);
1110 break;
1111 }
1112
1113 return ret;
1114}
1115
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001116static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001117 union perf_event *event,
1118 struct perf_sample *sample __maybe_unused,
1119 struct machine *machine)
1120{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001121 struct trace *trace = container_of(tool, struct trace, tool);
1122 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001123}
1124
1125static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
1126{
1127 int err = symbol__init();
1128
1129 if (err)
1130 return err;
1131
David Ahern8fb598e2013-09-28 13:13:00 -06001132 trace->host = machine__new_host();
1133 if (trace->host == NULL)
1134 return -ENOMEM;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001135
1136 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001137 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001138 trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001139 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001140 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001141 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
David Ahern8fb598e2013-09-28 13:13:00 -06001142 trace->host);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001143 }
1144
1145 if (err)
1146 symbol__exit();
1147
1148 return err;
1149}
1150
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001151static int syscall__set_arg_fmts(struct syscall *sc)
1152{
1153 struct format_field *field;
1154 int idx = 0;
1155
1156 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
1157 if (sc->arg_scnprintf == NULL)
1158 return -1;
1159
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001160 if (sc->fmt)
1161 sc->arg_parm = sc->fmt->arg_parm;
1162
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001163 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -03001164 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
1165 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
1166 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001167 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
1168 ++idx;
1169 }
1170
1171 return 0;
1172}
1173
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001174static int trace__read_syscall_info(struct trace *trace, int id)
1175{
1176 char tp_name[128];
1177 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001178 const char *name = audit_syscall_to_name(id, trace->audit_machine);
1179
1180 if (name == NULL)
1181 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001182
1183 if (id > trace->syscalls.max) {
1184 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
1185
1186 if (nsyscalls == NULL)
1187 return -1;
1188
1189 if (trace->syscalls.max != -1) {
1190 memset(nsyscalls + trace->syscalls.max + 1, 0,
1191 (id - trace->syscalls.max) * sizeof(*sc));
1192 } else {
1193 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
1194 }
1195
1196 trace->syscalls.table = nsyscalls;
1197 trace->syscalls.max = id;
1198 }
1199
1200 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001201 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001202
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001203 if (trace->ev_qualifier) {
1204 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
1205
1206 if (!(in ^ trace->not_ev_qualifier)) {
1207 sc->filtered = true;
1208 /*
1209 * No need to do read tracepoint information since this will be
1210 * filtered out.
1211 */
1212 return 0;
1213 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001214 }
1215
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -03001216 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001217
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -03001218 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
1219 sc->tp_format = event_format__new("syscalls", tp_name);
1220
1221 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
1222 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
1223 sc->tp_format = event_format__new("syscalls", tp_name);
1224 }
1225
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001226 if (sc->tp_format == NULL)
1227 return -1;
1228
1229 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001230}
1231
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001232static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001233 unsigned long *args, struct trace *trace,
1234 struct thread *thread)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001235{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001236 size_t printed = 0;
1237
1238 if (sc->tp_format != NULL) {
1239 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001240 u8 bit = 1;
1241 struct syscall_arg arg = {
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001242 .idx = 0,
1243 .mask = 0,
1244 .trace = trace,
1245 .thread = thread,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001246 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001247
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001248 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001249 field = field->next, ++arg.idx, bit <<= 1) {
1250 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001251 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -03001252 /*
1253 * Suppress this argument if its value is zero and
1254 * and we don't have a string associated in an
1255 * strarray for it.
1256 */
1257 if (args[arg.idx] == 0 &&
1258 !(sc->arg_scnprintf &&
1259 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
1260 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -03001261 continue;
1262
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001263 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001264 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001265 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
1266 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -03001267 if (sc->arg_parm)
1268 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001269 printed += sc->arg_scnprintf[arg.idx](bf + printed,
1270 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001271 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -03001272 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001273 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -03001274 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001275 }
1276 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -03001277 int i = 0;
1278
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001279 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001280 printed += scnprintf(bf + printed, size - printed,
1281 "%sarg%d: %ld",
1282 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001283 ++i;
1284 }
1285 }
1286
1287 return printed;
1288}
1289
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001290typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
1291 struct perf_sample *sample);
1292
1293static struct syscall *trace__syscall_info(struct trace *trace,
1294 struct perf_evsel *evsel,
1295 struct perf_sample *sample)
1296{
1297 int id = perf_evsel__intval(evsel, sample, "id");
1298
1299 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -03001300
1301 /*
1302 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
1303 * before that, leaving at a higher verbosity level till that is
1304 * explained. Reproduced with plain ftrace with:
1305 *
1306 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1307 * grep "NR -1 " /t/trace_pipe
1308 *
1309 * After generating some load on the machine.
1310 */
1311 if (verbose > 1) {
1312 static u64 n;
1313 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1314 id, perf_evsel__name(evsel), ++n);
1315 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001316 return NULL;
1317 }
1318
1319 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1320 trace__read_syscall_info(trace, id))
1321 goto out_cant_read;
1322
1323 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1324 goto out_cant_read;
1325
1326 return &trace->syscalls.table[id];
1327
1328out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001329 if (verbose) {
1330 fprintf(trace->output, "Problems reading syscall %d", id);
1331 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1332 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1333 fputs(" information\n", trace->output);
1334 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001335 return NULL;
1336}
1337
1338static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1339 struct perf_sample *sample)
1340{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001341 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001342 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001343 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001344 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001345 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001346 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001347
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001348 if (sc == NULL)
1349 return -1;
1350
1351 if (sc->filtered)
1352 return 0;
1353
David Ahern8fb598e2013-09-28 13:13:00 -06001354 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001355 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001356 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001357 return -1;
1358
1359 args = perf_evsel__rawptr(evsel, sample, "args");
1360 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001361 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001362 return -1;
1363 }
1364
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001365 ttrace = thread->priv;
1366
1367 if (ttrace->entry_str == NULL) {
1368 ttrace->entry_str = malloc(1024);
1369 if (!ttrace->entry_str)
1370 return -1;
1371 }
1372
1373 ttrace->entry_time = sample->time;
1374 msg = ttrace->entry_str;
1375 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1376
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001377 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed,
1378 args, trace, thread);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001379
1380 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001381 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001382 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1383 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001384 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001385 } else
1386 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001387
1388 return 0;
1389}
1390
1391static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1392 struct perf_sample *sample)
1393{
1394 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001395 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001396 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001397 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001398 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001399
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001400 if (sc == NULL)
1401 return -1;
1402
1403 if (sc->filtered)
1404 return 0;
1405
David Ahern8fb598e2013-09-28 13:13:00 -06001406 thread = machine__findnew_thread(trace->host, sample->pid, sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001407 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001408 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001409 return -1;
1410
1411 ret = perf_evsel__intval(evsel, sample, "ret");
1412
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001413 ttrace = thread->priv;
1414
1415 ttrace->exit_time = sample->time;
1416
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001417 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001418 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001419 if (trace__filter_duration(trace, duration))
1420 goto out;
1421 } else if (trace->duration_filter)
1422 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001423
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001424 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001425
1426 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001427 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001428 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001429 fprintf(trace->output, " ... [");
1430 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1431 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001432 }
1433
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001434 if (sc->fmt == NULL) {
1435signed_print:
1436 fprintf(trace->output, ") = %d", ret);
1437 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001438 char bf[256];
1439 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1440 *e = audit_errno_to_name(-ret);
1441
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001442 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001443 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001444 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001445 else if (sc->fmt->hexret)
1446 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001447 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001448 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001449
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001450 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001451out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001452 ttrace->entry_pending = false;
1453
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001454 return 0;
1455}
1456
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001457static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1458 struct perf_sample *sample)
1459{
1460 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1461 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
David Ahern8fb598e2013-09-28 13:13:00 -06001462 struct thread *thread = machine__findnew_thread(trace->host,
Adrian Hunter314add62013-08-27 11:23:03 +03001463 sample->pid,
1464 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001465 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001466
1467 if (ttrace == NULL)
1468 goto out_dump;
1469
1470 ttrace->runtime_ms += runtime_ms;
1471 trace->runtime_ms += runtime_ms;
1472 return 0;
1473
1474out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001475 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001476 evsel->name,
1477 perf_evsel__strval(evsel, sample, "comm"),
1478 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1479 runtime,
1480 perf_evsel__intval(evsel, sample, "vruntime"));
1481 return 0;
1482}
1483
David Ahernbdc89662013-08-28 22:29:53 -06001484static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1485{
1486 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1487 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1488 return false;
1489
1490 if (trace->pid_list || trace->tid_list)
1491 return true;
1492
1493 return false;
1494}
1495
David Ahern6810fc92013-08-28 22:29:52 -06001496static int trace__process_sample(struct perf_tool *tool,
1497 union perf_event *event __maybe_unused,
1498 struct perf_sample *sample,
1499 struct perf_evsel *evsel,
1500 struct machine *machine __maybe_unused)
1501{
1502 struct trace *trace = container_of(tool, struct trace, tool);
1503 int err = 0;
1504
1505 tracepoint_handler handler = evsel->handler.func;
1506
David Ahernbdc89662013-08-28 22:29:53 -06001507 if (skip_sample(trace, sample))
1508 return 0;
1509
David Ahern4bb09192013-09-04 12:37:43 -06001510 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001511 trace->base_time = sample->time;
1512
1513 if (handler)
1514 handler(trace, evsel, sample);
1515
1516 return err;
1517}
1518
1519static bool
1520perf_session__has_tp(struct perf_session *session, const char *name)
1521{
1522 struct perf_evsel *evsel;
1523
1524 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1525
1526 return evsel != NULL;
1527}
1528
David Ahernbdc89662013-08-28 22:29:53 -06001529static int parse_target_str(struct trace *trace)
1530{
1531 if (trace->opts.target.pid) {
1532 trace->pid_list = intlist__new(trace->opts.target.pid);
1533 if (trace->pid_list == NULL) {
1534 pr_err("Error parsing process id string\n");
1535 return -EINVAL;
1536 }
1537 }
1538
1539 if (trace->opts.target.tid) {
1540 trace->tid_list = intlist__new(trace->opts.target.tid);
1541 if (trace->tid_list == NULL) {
1542 pr_err("Error parsing thread id string\n");
1543 return -EINVAL;
1544 }
1545 }
1546
1547 return 0;
1548}
1549
David Ahern5e2485b2013-09-28 13:13:01 -06001550static int trace__record(int argc, const char **argv)
1551{
1552 unsigned int rec_argc, i, j;
1553 const char **rec_argv;
1554 const char * const record_args[] = {
1555 "record",
1556 "-R",
1557 "-m", "1024",
1558 "-c", "1",
1559 "-e", "raw_syscalls:sys_enter,raw_syscalls:sys_exit",
1560 };
1561
1562 rec_argc = ARRAY_SIZE(record_args) + argc;
1563 rec_argv = calloc(rec_argc + 1, sizeof(char *));
1564
1565 if (rec_argv == NULL)
1566 return -ENOMEM;
1567
1568 for (i = 0; i < ARRAY_SIZE(record_args); i++)
1569 rec_argv[i] = record_args[i];
1570
1571 for (j = 0; j < (unsigned int)argc; j++, i++)
1572 rec_argv[i] = argv[j];
1573
1574 return cmd_record(i, rec_argv, NULL);
1575}
1576
Namhyung Kimf15eb532012-10-05 14:02:16 +09001577static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001578{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001579 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001580 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001581 int err = -1, i;
1582 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001583 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001584
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001585 trace->live = true;
1586
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001587 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001588 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001589 goto out;
1590 }
1591
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001592 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1593 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001594 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001595 goto out_delete_evlist;
1596 }
1597
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001598 if (trace->sched &&
1599 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1600 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001601 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001602 goto out_delete_evlist;
1603 }
1604
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001605 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1606 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001607 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001608 goto out_delete_evlist;
1609 }
1610
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001611 err = trace__symbols_init(trace, evlist);
1612 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001613 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001614 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001615 }
1616
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001617 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001618
Namhyung Kimf15eb532012-10-05 14:02:16 +09001619 signal(SIGCHLD, sig_handler);
1620 signal(SIGINT, sig_handler);
1621
1622 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001623 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001624 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001625 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001626 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001627 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001628 }
1629 }
1630
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001631 err = perf_evlist__open(evlist);
1632 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001633 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001634 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001635 }
1636
1637 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1638 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001639 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001640 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001641 }
1642
1643 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001644
1645 if (forks)
1646 perf_evlist__start_workload(evlist);
1647
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001648 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001649again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001650 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001651
1652 for (i = 0; i < evlist->nr_mmaps; i++) {
1653 union perf_event *event;
1654
1655 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1656 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001657 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001658 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001659
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001660 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001661
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001662 err = perf_evlist__parse_sample(evlist, event, &sample);
1663 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001664 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001665 continue;
1666 }
1667
David Ahern4bb09192013-09-04 12:37:43 -06001668 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669 trace->base_time = sample.time;
1670
1671 if (type != PERF_RECORD_SAMPLE) {
David Ahern8fb598e2013-09-28 13:13:00 -06001672 trace__process_event(trace, trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001673 continue;
1674 }
1675
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001676 evsel = perf_evlist__id2evsel(evlist, sample.id);
1677 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001678 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001679 continue;
1680 }
1681
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001682 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001683 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 -03001684 perf_evsel__name(evsel), sample.tid,
1685 sample.cpu, sample.raw_size);
1686 continue;
1687 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001688
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001689 handler = evsel->handler.func;
1690 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001691
1692 if (done)
1693 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001694 }
1695 }
1696
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001697 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001698 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001699 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001700
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001701 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001702 }
1703
1704 if (done)
1705 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001706
1707 goto again;
1708
Namhyung Kim3beb0862013-03-15 14:48:50 +09001709out_unmap_evlist:
1710 perf_evlist__munmap(evlist);
1711out_close_evlist:
1712 perf_evlist__close(evlist);
1713out_delete_maps:
1714 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001715out_delete_evlist:
1716 perf_evlist__delete(evlist);
1717out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001718 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001719 return err;
1720}
1721
David Ahern6810fc92013-08-28 22:29:52 -06001722static int trace__replay(struct trace *trace)
1723{
1724 const struct perf_evsel_str_handler handlers[] = {
1725 { "raw_syscalls:sys_enter", trace__sys_enter, },
1726 { "raw_syscalls:sys_exit", trace__sys_exit, },
1727 };
1728
1729 struct perf_session *session;
1730 int err = -1;
1731
1732 trace->tool.sample = trace__process_sample;
1733 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001734 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001735 trace->tool.comm = perf_event__process_comm;
1736 trace->tool.exit = perf_event__process_exit;
1737 trace->tool.fork = perf_event__process_fork;
1738 trace->tool.attr = perf_event__process_attr;
1739 trace->tool.tracing_data = perf_event__process_tracing_data;
1740 trace->tool.build_id = perf_event__process_build_id;
1741
1742 trace->tool.ordered_samples = true;
1743 trace->tool.ordering_requires_timestamps = true;
1744
1745 /* add tid to output */
1746 trace->multiple_threads = true;
1747
1748 if (symbol__init() < 0)
1749 return -1;
1750
1751 session = perf_session__new(input_name, O_RDONLY, 0, false,
1752 &trace->tool);
1753 if (session == NULL)
1754 return -ENOMEM;
1755
David Ahern8fb598e2013-09-28 13:13:00 -06001756 trace->host = &session->machines.host;
1757
David Ahern6810fc92013-08-28 22:29:52 -06001758 err = perf_session__set_tracepoints_handlers(session, handlers);
1759 if (err)
1760 goto out;
1761
1762 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1763 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1764 goto out;
1765 }
1766
1767 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1768 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1769 goto out;
1770 }
1771
David Ahernbdc89662013-08-28 22:29:53 -06001772 err = parse_target_str(trace);
1773 if (err != 0)
1774 goto out;
1775
David Ahern6810fc92013-08-28 22:29:52 -06001776 setup_pager();
1777
1778 err = perf_session__process_events(session, &trace->tool);
1779 if (err)
1780 pr_err("Failed to process events, error %d", err);
1781
1782out:
1783 perf_session__delete(session);
1784
1785 return err;
1786}
1787
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001788static size_t trace__fprintf_threads_header(FILE *fp)
1789{
1790 size_t printed;
1791
1792 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1793 printed += fprintf(fp," __) Summary of events (__\n\n");
1794 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1795 printed += fprintf(fp," _____________________________________________________________________\n\n");
1796
1797 return printed;
1798}
1799
David Ahern896cbb52013-09-28 13:12:59 -06001800/* struct used to pass data to per-thread function */
1801struct summary_data {
1802 FILE *fp;
1803 struct trace *trace;
1804 size_t printed;
1805};
1806
1807static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1808{
1809 struct summary_data *data = priv;
1810 FILE *fp = data->fp;
1811 size_t printed = data->printed;
1812 struct trace *trace = data->trace;
1813 struct thread_trace *ttrace = thread->priv;
1814 const char *color;
1815 double ratio;
1816
1817 if (ttrace == NULL)
1818 return 0;
1819
1820 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1821
1822 color = PERF_COLOR_NORMAL;
1823 if (ratio > 50.0)
1824 color = PERF_COLOR_RED;
1825 else if (ratio > 25.0)
1826 color = PERF_COLOR_GREEN;
1827 else if (ratio > 5.0)
1828 color = PERF_COLOR_YELLOW;
1829
1830 printed += color_fprintf(fp, color, "%20s", thread->comm);
1831 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1832 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1833 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1834
1835 data->printed += printed;
1836
1837 return 0;
1838}
1839
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001840static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1841{
David Ahern896cbb52013-09-28 13:12:59 -06001842 struct summary_data data = {
1843 .fp = fp,
1844 .trace = trace
1845 };
1846 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001847
David Ahern896cbb52013-09-28 13:12:59 -06001848 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001849
David Ahern896cbb52013-09-28 13:12:59 -06001850 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001851}
1852
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001853static int trace__set_duration(const struct option *opt, const char *str,
1854 int unset __maybe_unused)
1855{
1856 struct trace *trace = opt->value;
1857
1858 trace->duration_filter = atof(str);
1859 return 0;
1860}
1861
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001862static int trace__open_output(struct trace *trace, const char *filename)
1863{
1864 struct stat st;
1865
1866 if (!stat(filename, &st) && st.st_size) {
1867 char oldname[PATH_MAX];
1868
1869 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1870 unlink(oldname);
1871 rename(filename, oldname);
1872 }
1873
1874 trace->output = fopen(filename, "w");
1875
1876 return trace->output == NULL ? -errno : 0;
1877}
1878
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001879int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1880{
1881 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001882 "perf trace [<options>] [<command>]",
1883 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06001884 "perf trace record [<options>] [<command>]",
1885 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001886 NULL
1887 };
1888 struct trace trace = {
1889 .audit_machine = audit_detect_machine(),
1890 .syscalls = {
1891 . max = -1,
1892 },
1893 .opts = {
1894 .target = {
1895 .uid = UINT_MAX,
1896 .uses_mmap = true,
1897 },
1898 .user_freq = UINT_MAX,
1899 .user_interval = ULLONG_MAX,
1900 .no_delay = true,
1901 .mmap_pages = 1024,
1902 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001903 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001904 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001905 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001906 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001907 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001908 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001909 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1910 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001911 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1912 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001913 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001914 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001915 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1916 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001917 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001918 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001919 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001920 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001921 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001922 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001923 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001924 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001925 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1926 "number of mmap data pages",
1927 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001928 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001929 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001930 OPT_CALLBACK(0, "duration", &trace, "float",
1931 "show only events with duration > N.M ms",
1932 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001933 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001934 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001935 OPT_BOOLEAN('T', "time", &trace.full_time,
1936 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001937 OPT_END()
1938 };
1939 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001940 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001941
David Ahern5e2485b2013-09-28 13:13:01 -06001942 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
1943 return trace__record(argc-2, &argv[2]);
1944
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001945 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001946
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001947 if (output_name != NULL) {
1948 err = trace__open_output(&trace, output_name);
1949 if (err < 0) {
1950 perror("failed to create output file");
1951 goto out;
1952 }
1953 }
1954
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001955 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001956 const char *s = ev_qualifier_str;
1957
1958 trace.not_ev_qualifier = *s == '!';
1959 if (trace.not_ev_qualifier)
1960 ++s;
1961 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001962 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001963 fputs("Not enough memory to parse event qualifier",
1964 trace.output);
1965 err = -ENOMEM;
1966 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001967 }
1968 }
1969
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001970 err = perf_target__validate(&trace.opts.target);
1971 if (err) {
1972 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001973 fprintf(trace.output, "%s", bf);
1974 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001975 }
1976
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001977 err = perf_target__parse_uid(&trace.opts.target);
1978 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001979 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001980 fprintf(trace.output, "%s", bf);
1981 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001982 }
1983
Namhyung Kimf15eb532012-10-05 14:02:16 +09001984 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001985 trace.opts.target.system_wide = true;
1986
David Ahern6810fc92013-08-28 22:29:52 -06001987 if (input_name)
1988 err = trace__replay(&trace);
1989 else
1990 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001991
1992 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001993 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001994
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001995out_close:
1996 if (output_name != NULL)
1997 fclose(trace.output);
1998out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001999 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002000}