blob: 5496546b7c5ca218f22258261fdfc98cf25a404d [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) ||
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301593 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit))
1594 goto out_error_tp;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001595
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001596 if (trace->sched &&
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301597 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1598 trace__sched_stat_runtime))
1599 goto out_error_tp;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001600
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001601 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1602 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001603 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001604 goto out_delete_evlist;
1605 }
1606
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001607 err = trace__symbols_init(trace, evlist);
1608 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001609 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001610 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001611 }
1612
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001613 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001614
Namhyung Kimf15eb532012-10-05 14:02:16 +09001615 signal(SIGCHLD, sig_handler);
1616 signal(SIGINT, sig_handler);
1617
1618 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001619 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001620 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001621 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001622 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001623 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001624 }
1625 }
1626
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001627 err = perf_evlist__open(evlist);
1628 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001629 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001630 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001631 }
1632
1633 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1634 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001635 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001636 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001637 }
1638
1639 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001640
1641 if (forks)
1642 perf_evlist__start_workload(evlist);
1643
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001644 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001645again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001646 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001647
1648 for (i = 0; i < evlist->nr_mmaps; i++) {
1649 union perf_event *event;
1650
1651 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1652 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001653 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001654 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001655
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001656 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001657
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001658 err = perf_evlist__parse_sample(evlist, event, &sample);
1659 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001660 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001661 continue;
1662 }
1663
David Ahern4bb09192013-09-04 12:37:43 -06001664 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001665 trace->base_time = sample.time;
1666
1667 if (type != PERF_RECORD_SAMPLE) {
David Ahern8fb598e2013-09-28 13:13:00 -06001668 trace__process_event(trace, trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001669 continue;
1670 }
1671
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001672 evsel = perf_evlist__id2evsel(evlist, sample.id);
1673 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001674 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001675 continue;
1676 }
1677
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001678 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001679 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 -03001680 perf_evsel__name(evsel), sample.tid,
1681 sample.cpu, sample.raw_size);
1682 continue;
1683 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001684
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001685 handler = evsel->handler.func;
1686 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001687
1688 if (done)
1689 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001690 }
1691 }
1692
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001693 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001694 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001695 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001696
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001697 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001698 }
1699
1700 if (done)
1701 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001702
1703 goto again;
1704
Namhyung Kim3beb0862013-03-15 14:48:50 +09001705out_unmap_evlist:
1706 perf_evlist__munmap(evlist);
1707out_close_evlist:
1708 perf_evlist__close(evlist);
1709out_delete_maps:
1710 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001711out_delete_evlist:
1712 perf_evlist__delete(evlist);
1713out:
Arnaldo Carvalho de Melo75b757ca2013-09-24 11:04:32 -03001714 trace->live = false;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001715 return err;
Ramkumar Ramachandra87f91862013-10-04 10:47:31 +05301716out_error_tp:
1717 switch(errno) {
1718 case ENOENT:
1719 fputs("Error:\tUnable to find debugfs\n"
1720 "Hint:\tWas your kernel was compiled with debugfs support?\n"
1721 "Hint:\tIs the debugfs filesystem mounted?\n"
1722 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'\n",
1723 trace->output);
1724 break;
1725 case EACCES:
1726 fprintf(trace->output,
1727 "Error:\tNo permissions to read %s/tracing/events/raw_syscalls\n"
1728 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1729 debugfs_mountpoint, debugfs_mountpoint);
1730 break;
1731 default: {
1732 char bf[256];
1733 fprintf(trace->output, "Can't trace: %s\n",
1734 strerror_r(errno, bf, sizeof(bf)));
1735 }
1736 break;
1737 }
1738 goto out_delete_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001739}
1740
David Ahern6810fc92013-08-28 22:29:52 -06001741static int trace__replay(struct trace *trace)
1742{
1743 const struct perf_evsel_str_handler handlers[] = {
1744 { "raw_syscalls:sys_enter", trace__sys_enter, },
1745 { "raw_syscalls:sys_exit", trace__sys_exit, },
1746 };
1747
1748 struct perf_session *session;
1749 int err = -1;
1750
1751 trace->tool.sample = trace__process_sample;
1752 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001753 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001754 trace->tool.comm = perf_event__process_comm;
1755 trace->tool.exit = perf_event__process_exit;
1756 trace->tool.fork = perf_event__process_fork;
1757 trace->tool.attr = perf_event__process_attr;
1758 trace->tool.tracing_data = perf_event__process_tracing_data;
1759 trace->tool.build_id = perf_event__process_build_id;
1760
1761 trace->tool.ordered_samples = true;
1762 trace->tool.ordering_requires_timestamps = true;
1763
1764 /* add tid to output */
1765 trace->multiple_threads = true;
1766
1767 if (symbol__init() < 0)
1768 return -1;
1769
1770 session = perf_session__new(input_name, O_RDONLY, 0, false,
1771 &trace->tool);
1772 if (session == NULL)
1773 return -ENOMEM;
1774
David Ahern8fb598e2013-09-28 13:13:00 -06001775 trace->host = &session->machines.host;
1776
David Ahern6810fc92013-08-28 22:29:52 -06001777 err = perf_session__set_tracepoints_handlers(session, handlers);
1778 if (err)
1779 goto out;
1780
1781 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1782 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1783 goto out;
1784 }
1785
1786 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1787 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1788 goto out;
1789 }
1790
David Ahernbdc89662013-08-28 22:29:53 -06001791 err = parse_target_str(trace);
1792 if (err != 0)
1793 goto out;
1794
David Ahern6810fc92013-08-28 22:29:52 -06001795 setup_pager();
1796
1797 err = perf_session__process_events(session, &trace->tool);
1798 if (err)
1799 pr_err("Failed to process events, error %d", err);
1800
1801out:
1802 perf_session__delete(session);
1803
1804 return err;
1805}
1806
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001807static size_t trace__fprintf_threads_header(FILE *fp)
1808{
1809 size_t printed;
1810
1811 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1812 printed += fprintf(fp," __) Summary of events (__\n\n");
1813 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1814 printed += fprintf(fp," _____________________________________________________________________\n\n");
1815
1816 return printed;
1817}
1818
David Ahern896cbb52013-09-28 13:12:59 -06001819/* struct used to pass data to per-thread function */
1820struct summary_data {
1821 FILE *fp;
1822 struct trace *trace;
1823 size_t printed;
1824};
1825
1826static int trace__fprintf_one_thread(struct thread *thread, void *priv)
1827{
1828 struct summary_data *data = priv;
1829 FILE *fp = data->fp;
1830 size_t printed = data->printed;
1831 struct trace *trace = data->trace;
1832 struct thread_trace *ttrace = thread->priv;
1833 const char *color;
1834 double ratio;
1835
1836 if (ttrace == NULL)
1837 return 0;
1838
1839 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1840
1841 color = PERF_COLOR_NORMAL;
1842 if (ratio > 50.0)
1843 color = PERF_COLOR_RED;
1844 else if (ratio > 25.0)
1845 color = PERF_COLOR_GREEN;
1846 else if (ratio > 5.0)
1847 color = PERF_COLOR_YELLOW;
1848
1849 printed += color_fprintf(fp, color, "%20s", thread->comm);
1850 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
1851 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1852 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1853
1854 data->printed += printed;
1855
1856 return 0;
1857}
1858
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001859static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1860{
David Ahern896cbb52013-09-28 13:12:59 -06001861 struct summary_data data = {
1862 .fp = fp,
1863 .trace = trace
1864 };
1865 data.printed = trace__fprintf_threads_header(fp);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001866
David Ahern896cbb52013-09-28 13:12:59 -06001867 machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001868
David Ahern896cbb52013-09-28 13:12:59 -06001869 return data.printed;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001870}
1871
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001872static int trace__set_duration(const struct option *opt, const char *str,
1873 int unset __maybe_unused)
1874{
1875 struct trace *trace = opt->value;
1876
1877 trace->duration_filter = atof(str);
1878 return 0;
1879}
1880
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001881static int trace__open_output(struct trace *trace, const char *filename)
1882{
1883 struct stat st;
1884
1885 if (!stat(filename, &st) && st.st_size) {
1886 char oldname[PATH_MAX];
1887
1888 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1889 unlink(oldname);
1890 rename(filename, oldname);
1891 }
1892
1893 trace->output = fopen(filename, "w");
1894
1895 return trace->output == NULL ? -errno : 0;
1896}
1897
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001898int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1899{
1900 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001901 "perf trace [<options>] [<command>]",
1902 "perf trace [<options>] -- <command> [<options>]",
David Ahern5e2485b2013-09-28 13:13:01 -06001903 "perf trace record [<options>] [<command>]",
1904 "perf trace record [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001905 NULL
1906 };
1907 struct trace trace = {
1908 .audit_machine = audit_detect_machine(),
1909 .syscalls = {
1910 . max = -1,
1911 },
1912 .opts = {
1913 .target = {
1914 .uid = UINT_MAX,
1915 .uses_mmap = true,
1916 },
1917 .user_freq = UINT_MAX,
1918 .user_interval = ULLONG_MAX,
1919 .no_delay = true,
1920 .mmap_pages = 1024,
1921 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001922 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001923 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001924 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001925 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001926 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001927 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001928 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1929 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001930 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1931 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001932 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001933 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001934 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1935 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001936 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001937 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001938 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001939 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001940 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001941 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001942 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001943 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001944 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1945 "number of mmap data pages",
1946 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001947 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001948 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001949 OPT_CALLBACK(0, "duration", &trace, "float",
1950 "show only events with duration > N.M ms",
1951 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001952 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001953 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001954 OPT_BOOLEAN('T', "time", &trace.full_time,
1955 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001956 OPT_END()
1957 };
1958 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001959 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001960
David Ahern5e2485b2013-09-28 13:13:01 -06001961 if ((argc > 1) && (strcmp(argv[1], "record") == 0))
1962 return trace__record(argc-2, &argv[2]);
1963
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001964 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001965
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001966 if (output_name != NULL) {
1967 err = trace__open_output(&trace, output_name);
1968 if (err < 0) {
1969 perror("failed to create output file");
1970 goto out;
1971 }
1972 }
1973
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001974 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001975 const char *s = ev_qualifier_str;
1976
1977 trace.not_ev_qualifier = *s == '!';
1978 if (trace.not_ev_qualifier)
1979 ++s;
1980 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001981 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001982 fputs("Not enough memory to parse event qualifier",
1983 trace.output);
1984 err = -ENOMEM;
1985 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001986 }
1987 }
1988
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001989 err = perf_target__validate(&trace.opts.target);
1990 if (err) {
1991 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001992 fprintf(trace.output, "%s", bf);
1993 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001994 }
1995
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001996 err = perf_target__parse_uid(&trace.opts.target);
1997 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001998 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001999 fprintf(trace.output, "%s", bf);
2000 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002001 }
2002
Namhyung Kimf15eb532012-10-05 14:02:16 +09002003 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09002004 trace.opts.target.system_wide = true;
2005
David Ahern6810fc92013-08-28 22:29:52 -06002006 if (input_name)
2007 err = trace__replay(&trace);
2008 else
2009 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002010
2011 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002012 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002013
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03002014out_close:
2015 if (output_name != NULL)
2016 fclose(trace.output);
2017out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03002018 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03002019}