blob: bf74217be22c87691169ab7f2a4c47ad699bec98 [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 Melo1f115cb2013-09-03 15:50:28 -030039 void *parm;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030040 u8 idx;
41 u8 mask;
42};
43
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -030044struct strarray {
45 int nr_entries;
46 const char **entries;
47};
48
49#define DEFINE_STRARRAY(array) struct strarray strarray__##array = { \
50 .nr_entries = ARRAY_SIZE(array), \
51 .entries = array, \
52}
53
54static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size,
55 struct syscall_arg *arg)
56{
57 int idx = arg->val;
58 struct strarray *sa = arg->parm;
59
60 if (idx < 0 || idx >= sa->nr_entries)
61 return scnprintf(bf, size, "%d", idx);
62
63 return scnprintf(bf, size, "%s", sa->entries[idx]);
64}
65
66#define SCA_STRARRAY syscall_arg__scnprintf_strarray
67
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030068static size_t syscall_arg__scnprintf_hex(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030069 struct syscall_arg *arg)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030070{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030071 return scnprintf(bf, size, "%#lx", arg->val);
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -030072}
73
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -030074#define SCA_HEX syscall_arg__scnprintf_hex
75
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -030076static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030077 struct syscall_arg *arg)
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030078{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -030079 int printed = 0, prot = arg->val;
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -030080
81 if (prot == PROT_NONE)
82 return scnprintf(bf, size, "NONE");
83#define P_MMAP_PROT(n) \
84 if (prot & PROT_##n) { \
85 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
86 prot &= ~PROT_##n; \
87 }
88
89 P_MMAP_PROT(EXEC);
90 P_MMAP_PROT(READ);
91 P_MMAP_PROT(WRITE);
92#ifdef PROT_SEM
93 P_MMAP_PROT(SEM);
94#endif
95 P_MMAP_PROT(GROWSDOWN);
96 P_MMAP_PROT(GROWSUP);
97#undef P_MMAP_PROT
98
99 if (prot)
100 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
101
102 return printed;
103}
104
105#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
106
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300107static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300108 struct syscall_arg *arg)
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300109{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300110 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300111
112#define P_MMAP_FLAG(n) \
113 if (flags & MAP_##n) { \
114 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
115 flags &= ~MAP_##n; \
116 }
117
118 P_MMAP_FLAG(SHARED);
119 P_MMAP_FLAG(PRIVATE);
Kyle McMartin41817812013-09-05 10:29:47 -0400120#ifdef MAP_32BIT
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300121 P_MMAP_FLAG(32BIT);
Kyle McMartin41817812013-09-05 10:29:47 -0400122#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300123 P_MMAP_FLAG(ANONYMOUS);
124 P_MMAP_FLAG(DENYWRITE);
125 P_MMAP_FLAG(EXECUTABLE);
126 P_MMAP_FLAG(FILE);
127 P_MMAP_FLAG(FIXED);
128 P_MMAP_FLAG(GROWSDOWN);
David Ahernf2935f32013-08-27 10:50:40 -0600129#ifdef MAP_HUGETLB
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300130 P_MMAP_FLAG(HUGETLB);
David Ahernf2935f32013-08-27 10:50:40 -0600131#endif
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300132 P_MMAP_FLAG(LOCKED);
133 P_MMAP_FLAG(NONBLOCK);
134 P_MMAP_FLAG(NORESERVE);
135 P_MMAP_FLAG(POPULATE);
136 P_MMAP_FLAG(STACK);
137#ifdef MAP_UNINITIALIZED
138 P_MMAP_FLAG(UNINITIALIZED);
139#endif
140#undef P_MMAP_FLAG
141
142 if (flags)
143 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
144
145 return printed;
146}
147
148#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
149
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300150static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300151 struct syscall_arg *arg)
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300152{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300153 int behavior = arg->val;
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300154
155 switch (behavior) {
156#define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
157 P_MADV_BHV(NORMAL);
158 P_MADV_BHV(RANDOM);
159 P_MADV_BHV(SEQUENTIAL);
160 P_MADV_BHV(WILLNEED);
161 P_MADV_BHV(DONTNEED);
162 P_MADV_BHV(REMOVE);
163 P_MADV_BHV(DONTFORK);
164 P_MADV_BHV(DOFORK);
165 P_MADV_BHV(HWPOISON);
166#ifdef MADV_SOFT_OFFLINE
167 P_MADV_BHV(SOFT_OFFLINE);
168#endif
169 P_MADV_BHV(MERGEABLE);
170 P_MADV_BHV(UNMERGEABLE);
David Ahernf2935f32013-08-27 10:50:40 -0600171#ifdef MADV_HUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300172 P_MADV_BHV(HUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600173#endif
174#ifdef MADV_NOHUGEPAGE
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300175 P_MADV_BHV(NOHUGEPAGE);
David Ahernf2935f32013-08-27 10:50:40 -0600176#endif
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300177#ifdef MADV_DONTDUMP
178 P_MADV_BHV(DONTDUMP);
179#endif
180#ifdef MADV_DODUMP
181 P_MADV_BHV(DODUMP);
182#endif
183#undef P_MADV_PHV
184 default: break;
185 }
186
187 return scnprintf(bf, size, "%#x", behavior);
188}
189
190#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
191
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300192static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
193 struct syscall_arg *arg)
194{
195 int printed = 0, op = arg->val;
196
197 if (op == 0)
198 return scnprintf(bf, size, "NONE");
199#define P_CMD(cmd) \
200 if ((op & LOCK_##cmd) == LOCK_##cmd) { \
201 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \
202 op &= ~LOCK_##cmd; \
203 }
204
205 P_CMD(SH);
206 P_CMD(EX);
207 P_CMD(NB);
208 P_CMD(UN);
209 P_CMD(MAND);
210 P_CMD(RW);
211 P_CMD(READ);
212 P_CMD(WRITE);
213#undef P_OP
214
215 if (op)
216 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op);
217
218 return printed;
219}
220
221#define SCA_FLOCK syscall_arg__scnprintf_flock
222
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300223static 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 -0300224{
225 enum syscall_futex_args {
226 SCF_UADDR = (1 << 0),
227 SCF_OP = (1 << 1),
228 SCF_VAL = (1 << 2),
229 SCF_TIMEOUT = (1 << 3),
230 SCF_UADDR2 = (1 << 4),
231 SCF_VAL3 = (1 << 5),
232 };
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300233 int op = arg->val;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300234 int cmd = op & FUTEX_CMD_MASK;
235 size_t printed = 0;
236
237 switch (cmd) {
238#define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300239 P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
240 P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
241 P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
242 P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break;
243 P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break;
244 P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300245 P_FUTEX_OP(WAKE_OP); break;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300246 P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
247 P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break;
248 P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break;
249 P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break;
250 P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break;
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300251 P_FUTEX_OP(WAIT_REQUEUE_PI); break;
252 default: printed = scnprintf(bf, size, "%#x", cmd); break;
253 }
254
255 if (op & FUTEX_PRIVATE_FLAG)
256 printed += scnprintf(bf + printed, size - printed, "|PRIV");
257
258 if (op & FUTEX_CLOCK_REALTIME)
259 printed += scnprintf(bf + printed, size - printed, "|CLKRT");
260
261 return printed;
262}
263
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300264#define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op
265
Arnaldo Carvalho de Meloeac032c2013-09-20 11:27:32 -0300266static const char *epoll_ctl_ops[] = { [1] = "ADD", "DEL", "MOD", };
267static DEFINE_STRARRAY(epoll_ctl_ops);
268
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300269static const char *itimers[] = { "REAL", "VIRTUAL", "PROF", };
270static DEFINE_STRARRAY(itimers);
271
Arnaldo Carvalho de Meloefe6b882013-09-03 16:15:12 -0300272static const char *whences[] = { "SET", "CUR", "END",
273#ifdef SEEK_DATA
274"DATA",
275#endif
276#ifdef SEEK_HOLE
277"HOLE",
278#endif
279};
280static DEFINE_STRARRAY(whences);
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300281
Arnaldo Carvalho de Melo80f587d2013-09-03 16:28:58 -0300282static const char *fcntl_cmds[] = {
283 "DUPFD", "GETFD", "SETFD", "GETFL", "SETFL", "GETLK", "SETLK",
284 "SETLKW", "SETOWN", "GETOWN", "SETSIG", "GETSIG", "F_GETLK64",
285 "F_SETLK64", "F_SETLKW64", "F_SETOWN_EX", "F_GETOWN_EX",
286 "F_GETOWNER_UIDS",
287};
288static DEFINE_STRARRAY(fcntl_cmds);
289
Arnaldo Carvalho de Meloc045bf02013-09-04 11:52:33 -0300290static const char *rlimit_resources[] = {
291 "CPU", "FSIZE", "DATA", "STACK", "CORE", "RSS", "NPROC", "NOFILE",
292 "MEMLOCK", "AS", "LOCKS", "SIGPENDING", "MSGQUEUE", "NICE", "RTPRIO",
293 "RTTIME",
294};
295static DEFINE_STRARRAY(rlimit_resources);
296
Arnaldo Carvalho de Meloeb5b1b12013-09-03 16:37:46 -0300297static const char *sighow[] = { "BLOCK", "UNBLOCK", "SETMASK", };
298static DEFINE_STRARRAY(sighow);
299
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300300static const char *socket_families[] = {
301 "UNSPEC", "LOCAL", "INET", "AX25", "IPX", "APPLETALK", "NETROM",
302 "BRIDGE", "ATMPVC", "X25", "INET6", "ROSE", "DECnet", "NETBEUI",
303 "SECURITY", "KEY", "NETLINK", "PACKET", "ASH", "ECONET", "ATMSVC",
304 "RDS", "SNA", "IRDA", "PPPOX", "WANPIPE", "LLC", "IB", "CAN", "TIPC",
305 "BLUETOOTH", "IUCV", "RXRPC", "ISDN", "PHONET", "IEEE802154", "CAIF",
306 "ALG", "NFC", "VSOCK",
307};
308static DEFINE_STRARRAY(socket_families);
309
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300310#ifndef SOCK_TYPE_MASK
311#define SOCK_TYPE_MASK 0xf
312#endif
313
314static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size,
315 struct syscall_arg *arg)
316{
317 size_t printed;
318 int type = arg->val,
319 flags = type & ~SOCK_TYPE_MASK;
320
321 type &= SOCK_TYPE_MASK;
322 /*
323 * Can't use a strarray, MIPS may override for ABI reasons.
324 */
325 switch (type) {
326#define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break;
327 P_SK_TYPE(STREAM);
328 P_SK_TYPE(DGRAM);
329 P_SK_TYPE(RAW);
330 P_SK_TYPE(RDM);
331 P_SK_TYPE(SEQPACKET);
332 P_SK_TYPE(DCCP);
333 P_SK_TYPE(PACKET);
334#undef P_SK_TYPE
335 default:
336 printed = scnprintf(bf, size, "%#x", type);
337 }
338
339#define P_SK_FLAG(n) \
340 if (flags & SOCK_##n) { \
341 printed += scnprintf(bf + printed, size - printed, "|%s", #n); \
342 flags &= ~SOCK_##n; \
343 }
344
345 P_SK_FLAG(CLOEXEC);
346 P_SK_FLAG(NONBLOCK);
347#undef P_SK_FLAG
348
349 if (flags)
350 printed += scnprintf(bf + printed, size - printed, "|%#x", flags);
351
352 return printed;
353}
354
355#define SCA_SK_TYPE syscall_arg__scnprintf_socket_type
356
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300357#ifndef MSG_PROBE
358#define MSG_PROBE 0x10
359#endif
360#ifndef MSG_SENDPAGE_NOTLAST
361#define MSG_SENDPAGE_NOTLAST 0x20000
362#endif
363#ifndef MSG_FASTOPEN
364#define MSG_FASTOPEN 0x20000000
365#endif
366
367static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
368 struct syscall_arg *arg)
369{
370 int printed = 0, flags = arg->val;
371
372 if (flags == 0)
373 return scnprintf(bf, size, "NONE");
374#define P_MSG_FLAG(n) \
375 if (flags & MSG_##n) { \
376 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
377 flags &= ~MSG_##n; \
378 }
379
380 P_MSG_FLAG(OOB);
381 P_MSG_FLAG(PEEK);
382 P_MSG_FLAG(DONTROUTE);
383 P_MSG_FLAG(TRYHARD);
384 P_MSG_FLAG(CTRUNC);
385 P_MSG_FLAG(PROBE);
386 P_MSG_FLAG(TRUNC);
387 P_MSG_FLAG(DONTWAIT);
388 P_MSG_FLAG(EOR);
389 P_MSG_FLAG(WAITALL);
390 P_MSG_FLAG(FIN);
391 P_MSG_FLAG(SYN);
392 P_MSG_FLAG(CONFIRM);
393 P_MSG_FLAG(RST);
394 P_MSG_FLAG(ERRQUEUE);
395 P_MSG_FLAG(NOSIGNAL);
396 P_MSG_FLAG(MORE);
397 P_MSG_FLAG(WAITFORONE);
398 P_MSG_FLAG(SENDPAGE_NOTLAST);
399 P_MSG_FLAG(FASTOPEN);
400 P_MSG_FLAG(CMSG_CLOEXEC);
401#undef P_MSG_FLAG
402
403 if (flags)
404 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
405
406 return printed;
407}
408
409#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags
410
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300411static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
412 struct syscall_arg *arg)
413{
414 size_t printed = 0;
415 int mode = arg->val;
416
417 if (mode == F_OK) /* 0 */
418 return scnprintf(bf, size, "F");
419#define P_MODE(n) \
420 if (mode & n##_OK) { \
421 printed += scnprintf(bf + printed, size - printed, "%s", #n); \
422 mode &= ~n##_OK; \
423 }
424
425 P_MODE(R);
426 P_MODE(W);
427 P_MODE(X);
428#undef P_MODE
429
430 if (mode)
431 printed += scnprintf(bf + printed, size - printed, "|%#x", mode);
432
433 return printed;
434}
435
436#define SCA_ACCMODE syscall_arg__scnprintf_access_mode
437
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300438static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300439 struct syscall_arg *arg)
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300440{
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300441 int printed = 0, flags = arg->val;
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300442
443 if (!(flags & O_CREAT))
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300444 arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300445
446 if (flags == 0)
447 return scnprintf(bf, size, "RDONLY");
448#define P_FLAG(n) \
449 if (flags & O_##n) { \
450 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
451 flags &= ~O_##n; \
452 }
453
454 P_FLAG(APPEND);
455 P_FLAG(ASYNC);
456 P_FLAG(CLOEXEC);
457 P_FLAG(CREAT);
458 P_FLAG(DIRECT);
459 P_FLAG(DIRECTORY);
460 P_FLAG(EXCL);
461 P_FLAG(LARGEFILE);
462 P_FLAG(NOATIME);
463 P_FLAG(NOCTTY);
464#ifdef O_NONBLOCK
465 P_FLAG(NONBLOCK);
466#elif O_NDELAY
467 P_FLAG(NDELAY);
468#endif
469#ifdef O_PATH
470 P_FLAG(PATH);
471#endif
472 P_FLAG(RDWR);
473#ifdef O_DSYNC
474 if ((flags & O_SYNC) == O_SYNC)
475 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC");
476 else {
477 P_FLAG(DSYNC);
478 }
479#else
480 P_FLAG(SYNC);
481#endif
482 P_FLAG(TRUNC);
483 P_FLAG(WRONLY);
484#undef P_FLAG
485
486 if (flags)
487 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
488
489 return printed;
490}
491
492#define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags
493
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300494static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
495 struct syscall_arg *arg)
496{
497 int printed = 0, flags = arg->val;
498
499 if (flags == 0)
500 return scnprintf(bf, size, "NONE");
501#define P_FLAG(n) \
502 if (flags & EFD_##n) { \
503 printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
504 flags &= ~EFD_##n; \
505 }
506
507 P_FLAG(SEMAPHORE);
508 P_FLAG(CLOEXEC);
509 P_FLAG(NONBLOCK);
510#undef P_FLAG
511
512 if (flags)
513 printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
514
515 return printed;
516}
517
518#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
519
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300520static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg)
521{
522 int sig = arg->val;
523
524 switch (sig) {
525#define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n)
526 P_SIGNUM(HUP);
527 P_SIGNUM(INT);
528 P_SIGNUM(QUIT);
529 P_SIGNUM(ILL);
530 P_SIGNUM(TRAP);
531 P_SIGNUM(ABRT);
532 P_SIGNUM(BUS);
533 P_SIGNUM(FPE);
534 P_SIGNUM(KILL);
535 P_SIGNUM(USR1);
536 P_SIGNUM(SEGV);
537 P_SIGNUM(USR2);
538 P_SIGNUM(PIPE);
539 P_SIGNUM(ALRM);
540 P_SIGNUM(TERM);
541 P_SIGNUM(STKFLT);
542 P_SIGNUM(CHLD);
543 P_SIGNUM(CONT);
544 P_SIGNUM(STOP);
545 P_SIGNUM(TSTP);
546 P_SIGNUM(TTIN);
547 P_SIGNUM(TTOU);
548 P_SIGNUM(URG);
549 P_SIGNUM(XCPU);
550 P_SIGNUM(XFSZ);
551 P_SIGNUM(VTALRM);
552 P_SIGNUM(PROF);
553 P_SIGNUM(WINCH);
554 P_SIGNUM(IO);
555 P_SIGNUM(PWR);
556 P_SIGNUM(SYS);
557 default: break;
558 }
559
560 return scnprintf(bf, size, "%#x", sig);
561}
562
563#define SCA_SIGNUM syscall_arg__scnprintf_signum
564
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300565#define STRARRAY(arg, name, array) \
566 .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
567 .arg_parm = { [arg] = &strarray__##array, }
568
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300569static struct syscall_fmt {
570 const char *name;
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300571 const char *alias;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300572 size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300573 void *arg_parm[6];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300574 bool errmsg;
575 bool timeout;
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -0300576 bool hexret;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300577} syscall_fmts[] = {
Arnaldo Carvalho de Melo51108992013-09-04 11:42:27 -0300578 { .name = "access", .errmsg = true,
579 .arg_scnprintf = { [1] = SCA_ACCMODE, /* mode */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300580 { .name = "arch_prctl", .errmsg = true, .alias = "prctl", },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300581 { .name = "brk", .hexret = true,
582 .arg_scnprintf = { [0] = SCA_HEX, /* brk */ }, },
Arnaldo Carvalho de Meloa14bb862013-07-30 16:38:23 -0300583 { .name = "connect", .errmsg = true, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300584 { .name = "epoll_ctl", .errmsg = true, STRARRAY(1, op, epoll_ctl_ops), },
Arnaldo Carvalho de Melo49af9e92013-09-12 12:18:56 -0300585 { .name = "eventfd2", .errmsg = true,
586 .arg_scnprintf = { [1] = SCA_EFD_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300587 { .name = "fcntl", .errmsg = true, STRARRAY(1, cmd, fcntl_cmds), },
Arnaldo Carvalho de Melo5cea6ff2013-09-20 11:49:50 -0300588 { .name = "flock", .errmsg = true,
589 .arg_scnprintf = { [1] = SCA_FLOCK, /* cmd */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300590 { .name = "fstat", .errmsg = true, .alias = "newfstat", },
591 { .name = "fstatat", .errmsg = true, .alias = "newfstatat", },
Arnaldo Carvalho de Melof9da0b02013-09-02 13:46:44 -0300592 { .name = "futex", .errmsg = true,
593 .arg_scnprintf = { [1] = SCA_FUTEX_OP, /* op */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300594 { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), },
595 { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300596 { .name = "ioctl", .errmsg = true,
597 .arg_scnprintf = { [2] = SCA_HEX, /* arg */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300598 { .name = "kill", .errmsg = true,
599 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300600 { .name = "lseek", .errmsg = true, STRARRAY(2, whence, whences), },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300601 { .name = "lstat", .errmsg = true, .alias = "newlstat", },
Arnaldo Carvalho de Melo9e9716d2013-08-23 10:06:41 -0300602 { .name = "madvise", .errmsg = true,
603 .arg_scnprintf = { [0] = SCA_HEX, /* start */
604 [2] = SCA_MADV_BHV, /* behavior */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300605 { .name = "mmap", .hexret = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300606 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
Arnaldo Carvalho de Melo941557e2013-08-23 10:48:33 -0300607 [2] = SCA_MMAP_PROT, /* prot */
608 [3] = SCA_MMAP_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300609 { .name = "mprotect", .errmsg = true,
Arnaldo Carvalho de Meloae685382013-08-20 17:44:42 -0300610 .arg_scnprintf = { [0] = SCA_HEX, /* start */
611 [2] = SCA_MMAP_PROT, /* prot */ }, },
612 { .name = "mremap", .hexret = true,
613 .arg_scnprintf = { [0] = SCA_HEX, /* addr */
614 [4] = SCA_HEX, /* new_addr */ }, },
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300615 { .name = "munmap", .errmsg = true,
616 .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
Arnaldo Carvalho de Melobe65a892013-09-02 16:22:31 -0300617 { .name = "open", .errmsg = true,
618 .arg_scnprintf = { [1] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo31cd3852013-09-02 16:40:40 -0300619 { .name = "open_by_handle_at", .errmsg = true,
620 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
621 { .name = "openat", .errmsg = true,
622 .arg_scnprintf = { [2] = SCA_OPEN_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300623 { .name = "poll", .errmsg = true, .timeout = true, },
624 { .name = "ppoll", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300625 { .name = "pread", .errmsg = true, .alias = "pread64", },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300626 { .name = "prlimit64", .errmsg = true, STRARRAY(1, resource, rlimit_resources), },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300627 { .name = "pwrite", .errmsg = true, .alias = "pwrite64", },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300628 { .name = "read", .errmsg = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300629 { .name = "recvfrom", .errmsg = true,
630 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
631 { .name = "recvmmsg", .errmsg = true,
632 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
633 { .name = "recvmsg", .errmsg = true,
634 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300635 { .name = "rt_sigaction", .errmsg = true,
636 .arg_scnprintf = { [0] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300637 { .name = "rt_sigprocmask", .errmsg = true, STRARRAY(0, how, sighow), },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300638 { .name = "rt_sigqueueinfo", .errmsg = true,
639 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
640 { .name = "rt_tgsigqueueinfo", .errmsg = true,
641 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300642 { .name = "select", .errmsg = true, .timeout = true, },
Arnaldo Carvalho de Melob2cc99fd2013-09-12 11:54:48 -0300643 { .name = "sendmmsg", .errmsg = true,
644 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
645 { .name = "sendmsg", .errmsg = true,
646 .arg_scnprintf = { [2] = SCA_MSG_FLAGS, /* flags */ }, },
647 { .name = "sendto", .errmsg = true,
648 .arg_scnprintf = { [3] = SCA_MSG_FLAGS, /* flags */ }, },
Arnaldo Carvalho de Melo453350d2013-09-20 12:13:37 -0300649 { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), },
650 { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300651 { .name = "socket", .errmsg = true,
Arnaldo Carvalho de Meloa28b24b2013-09-04 11:00:44 -0300652 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
653 [1] = SCA_SK_TYPE, /* type */ },
Arnaldo Carvalho de Meloe10bce82013-09-04 10:27:41 -0300654 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Melo07120aa2013-09-20 12:24:20 -0300655 { .name = "socketpair", .errmsg = true,
656 .arg_scnprintf = { [0] = SCA_STRARRAY, /* family */
657 [1] = SCA_SK_TYPE, /* type */ },
658 .arg_parm = { [0] = &strarray__socket_families, /* family */ }, },
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300659 { .name = "stat", .errmsg = true, .alias = "newstat", },
Arnaldo Carvalho de Melo8bad5b02013-09-03 17:17:15 -0300660 { .name = "tgkill", .errmsg = true,
661 .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, },
662 { .name = "tkill", .errmsg = true,
663 .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, },
Arnaldo Carvalho de Meloe5959682013-08-26 12:21:41 -0300664 { .name = "uname", .errmsg = true, .alias = "newuname", },
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300665};
666
667static int syscall_fmt__cmp(const void *name, const void *fmtp)
668{
669 const struct syscall_fmt *fmt = fmtp;
670 return strcmp(name, fmt->name);
671}
672
673static struct syscall_fmt *syscall_fmt__find(const char *name)
674{
675 const int nmemb = ARRAY_SIZE(syscall_fmts);
676 return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp);
677}
678
679struct syscall {
680 struct event_format *tp_format;
681 const char *name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300682 bool filtered;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300683 struct syscall_fmt *fmt;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300684 size_t (**arg_scnprintf)(char *bf, size_t size, struct syscall_arg *arg);
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300685 void **arg_parm;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300686};
687
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200688static size_t fprintf_duration(unsigned long t, FILE *fp)
689{
690 double duration = (double)t / NSEC_PER_MSEC;
691 size_t printed = fprintf(fp, "(");
692
693 if (duration >= 1.0)
694 printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration);
695 else if (duration >= 0.01)
696 printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration);
697 else
698 printed += color_fprintf(fp, PERF_COLOR_NORMAL, "%6.3f ms", duration);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300699 return printed + fprintf(fp, "): ");
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200700}
701
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300702struct thread_trace {
703 u64 entry_time;
704 u64 exit_time;
705 bool entry_pending;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300706 unsigned long nr_events;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300707 char *entry_str;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300708 double runtime_ms;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300709};
710
711static struct thread_trace *thread_trace__new(void)
712{
713 return zalloc(sizeof(struct thread_trace));
714}
715
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300716static struct thread_trace *thread__trace(struct thread *thread, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300717{
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300718 struct thread_trace *ttrace;
719
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300720 if (thread == NULL)
721 goto fail;
722
723 if (thread->priv == NULL)
724 thread->priv = thread_trace__new();
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300725
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300726 if (thread->priv == NULL)
727 goto fail;
728
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300729 ttrace = thread->priv;
730 ++ttrace->nr_events;
731
732 return ttrace;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300733fail:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300734 color_fprintf(fp, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300735 "WARNING: not enough memory, dropping samples!\n");
736 return NULL;
737}
738
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300739struct trace {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300740 struct perf_tool tool;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300741 int audit_machine;
742 struct {
743 int max;
744 struct syscall *table;
745 } syscalls;
746 struct perf_record_opts opts;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300747 struct machine host;
748 u64 base_time;
David Ahern4bb09192013-09-04 12:37:43 -0600749 bool full_time;
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300750 FILE *output;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -0300751 unsigned long nr_events;
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300752 struct strlist *ev_qualifier;
753 bool not_ev_qualifier;
David Ahernbdc89662013-08-28 22:29:53 -0600754 struct intlist *tid_list;
755 struct intlist *pid_list;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300756 bool sched;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300757 bool multiple_threads;
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300758 bool show_comm;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300759 double duration_filter;
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -0300760 double runtime_ms;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300761};
762
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -0300763static bool trace__filter_duration(struct trace *trace, double t)
764{
765 return t < (trace->duration_filter * NSEC_PER_MSEC);
766}
767
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300768static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp)
769{
770 double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC;
771
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200772 return fprintf(fp, "%10.3f ", ts);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300773}
774
Namhyung Kimf15eb532012-10-05 14:02:16 +0900775static bool done = false;
776
777static void sig_handler(int sig __maybe_unused)
778{
779 done = true;
780}
781
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300782static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread,
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200783 u64 duration, u64 tstamp, FILE *fp)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300784{
785 size_t printed = trace__fprintf_tstamp(trace, tstamp, fp);
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -0200786 printed += fprintf_duration(duration, fp);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300787
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300788 if (trace->multiple_threads) {
789 if (trace->show_comm)
790 printed += fprintf(fp, "%.14s/", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +0300791 printed += fprintf(fp, "%d ", thread->tid);
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -0300792 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300793
794 return printed;
795}
796
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300797static int trace__process_event(struct trace *trace, struct machine *machine,
798 union perf_event *event)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300799{
800 int ret = 0;
801
802 switch (event->header.type) {
803 case PERF_RECORD_LOST:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300804 color_fprintf(trace->output, PERF_COLOR_RED,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300805 "LOST %" PRIu64 " events!\n", event->lost.lost);
806 ret = machine__process_lost_event(machine, event);
807 default:
808 ret = machine__process_event(machine, event);
809 break;
810 }
811
812 return ret;
813}
814
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300815static int trace__tool_process(struct perf_tool *tool,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300816 union perf_event *event,
817 struct perf_sample *sample __maybe_unused,
818 struct machine *machine)
819{
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300820 struct trace *trace = container_of(tool, struct trace, tool);
821 return trace__process_event(trace, machine, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300822}
823
824static int trace__symbols_init(struct trace *trace, struct perf_evlist *evlist)
825{
826 int err = symbol__init();
827
828 if (err)
829 return err;
830
831 machine__init(&trace->host, "", HOST_KERNEL_ID);
832 machine__create_kernel_maps(&trace->host);
833
834 if (perf_target__has_task(&trace->opts.target)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300835 err = perf_event__synthesize_thread_map(&trace->tool, evlist->threads,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300836 trace__tool_process,
837 &trace->host);
838 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -0300839 err = perf_event__synthesize_threads(&trace->tool, trace__tool_process,
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300840 &trace->host);
841 }
842
843 if (err)
844 symbol__exit();
845
846 return err;
847}
848
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300849static int syscall__set_arg_fmts(struct syscall *sc)
850{
851 struct format_field *field;
852 int idx = 0;
853
854 sc->arg_scnprintf = calloc(sc->tp_format->format.nr_fields - 1, sizeof(void *));
855 if (sc->arg_scnprintf == NULL)
856 return -1;
857
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300858 if (sc->fmt)
859 sc->arg_parm = sc->fmt->arg_parm;
860
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300861 for (field = sc->tp_format->format.fields->next; field; field = field->next) {
Arnaldo Carvalho de Melobeccb2b2013-08-26 12:29:38 -0300862 if (sc->fmt && sc->fmt->arg_scnprintf[idx])
863 sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx];
864 else if (field->flags & FIELD_IS_POINTER)
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300865 sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex;
866 ++idx;
867 }
868
869 return 0;
870}
871
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300872static int trace__read_syscall_info(struct trace *trace, int id)
873{
874 char tp_name[128];
875 struct syscall *sc;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300876 const char *name = audit_syscall_to_name(id, trace->audit_machine);
877
878 if (name == NULL)
879 return -1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300880
881 if (id > trace->syscalls.max) {
882 struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc));
883
884 if (nsyscalls == NULL)
885 return -1;
886
887 if (trace->syscalls.max != -1) {
888 memset(nsyscalls + trace->syscalls.max + 1, 0,
889 (id - trace->syscalls.max) * sizeof(*sc));
890 } else {
891 memset(nsyscalls, 0, (id + 1) * sizeof(*sc));
892 }
893
894 trace->syscalls.table = nsyscalls;
895 trace->syscalls.max = id;
896 }
897
898 sc = trace->syscalls.table + id;
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300899 sc->name = name;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300900
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -0300901 if (trace->ev_qualifier) {
902 bool in = strlist__find(trace->ev_qualifier, name) != NULL;
903
904 if (!(in ^ trace->not_ev_qualifier)) {
905 sc->filtered = true;
906 /*
907 * No need to do read tracepoint information since this will be
908 * filtered out.
909 */
910 return 0;
911 }
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -0300912 }
913
Arnaldo Carvalho de Melo3a531262012-10-20 12:39:03 -0300914 sc->fmt = syscall_fmt__find(sc->name);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300915
Arnaldo Carvalho de Meloaec19302012-09-27 13:16:00 -0300916 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name);
917 sc->tp_format = event_format__new("syscalls", tp_name);
918
919 if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) {
920 snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias);
921 sc->tp_format = event_format__new("syscalls", tp_name);
922 }
923
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300924 if (sc->tp_format == NULL)
925 return -1;
926
927 return syscall__set_arg_fmts(sc);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300928}
929
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300930static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size,
931 unsigned long *args)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300932{
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300933 size_t printed = 0;
934
935 if (sc->tp_format != NULL) {
936 struct format_field *field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300937 u8 bit = 1;
938 struct syscall_arg arg = {
939 .idx = 0,
940 .mask = 0,
941 };
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300942
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300943 for (field = sc->tp_format->format.fields->next; field;
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300944 field = field->next, ++arg.idx, bit <<= 1) {
945 if (arg.mask & bit)
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300946 continue;
Arnaldo Carvalho de Melo4aa58232013-09-20 12:19:41 -0300947 /*
948 * Suppress this argument if its value is zero and
949 * and we don't have a string associated in an
950 * strarray for it.
951 */
952 if (args[arg.idx] == 0 &&
953 !(sc->arg_scnprintf &&
954 sc->arg_scnprintf[arg.idx] == SCA_STRARRAY &&
955 sc->arg_parm[arg.idx]))
Arnaldo Carvalho de Melo22ae5cf12013-09-12 11:27:34 -0300956 continue;
957
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300958 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300959 "%s%s: ", printed ? ", " : "", field->name);
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300960 if (sc->arg_scnprintf && sc->arg_scnprintf[arg.idx]) {
961 arg.val = args[arg.idx];
Arnaldo Carvalho de Melo1f115cb2013-09-03 15:50:28 -0300962 if (sc->arg_parm)
963 arg.parm = sc->arg_parm[arg.idx];
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300964 printed += sc->arg_scnprintf[arg.idx](bf + printed,
965 size - printed, &arg);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300966 } else {
Arnaldo Carvalho de Melo13d4ff32013-08-23 18:14:48 -0300967 printed += scnprintf(bf + printed, size - printed,
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300968 "%ld", args[arg.idx]);
Arnaldo Carvalho de Melo6e7eeb52013-09-02 10:39:21 -0300969 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300970 }
971 } else {
Arnaldo Carvalho de Melo01533e92013-09-03 12:20:12 -0300972 int i = 0;
973
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300974 while (i < 6) {
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -0300975 printed += scnprintf(bf + printed, size - printed,
976 "%sarg%d: %ld",
977 printed ? ", " : "", i, args[i]);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -0300978 ++i;
979 }
980 }
981
982 return printed;
983}
984
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -0300985typedef int (*tracepoint_handler)(struct trace *trace, struct perf_evsel *evsel,
986 struct perf_sample *sample);
987
988static struct syscall *trace__syscall_info(struct trace *trace,
989 struct perf_evsel *evsel,
990 struct perf_sample *sample)
991{
992 int id = perf_evsel__intval(evsel, sample, "id");
993
994 if (id < 0) {
Arnaldo Carvalho de Meloadaa18b2013-08-22 17:55:25 -0300995
996 /*
997 * XXX: Noticed on x86_64, reproduced as far back as 3.0.36, haven't tried
998 * before that, leaving at a higher verbosity level till that is
999 * explained. Reproduced with plain ftrace with:
1000 *
1001 * echo 1 > /t/events/raw_syscalls/sys_exit/enable
1002 * grep "NR -1 " /t/trace_pipe
1003 *
1004 * After generating some load on the machine.
1005 */
1006 if (verbose > 1) {
1007 static u64 n;
1008 fprintf(trace->output, "Invalid syscall %d id, skipping (%s, %" PRIu64 ") ...\n",
1009 id, perf_evsel__name(evsel), ++n);
1010 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001011 return NULL;
1012 }
1013
1014 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) &&
1015 trace__read_syscall_info(trace, id))
1016 goto out_cant_read;
1017
1018 if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL))
1019 goto out_cant_read;
1020
1021 return &trace->syscalls.table[id];
1022
1023out_cant_read:
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001024 if (verbose) {
1025 fprintf(trace->output, "Problems reading syscall %d", id);
1026 if (id <= trace->syscalls.max && trace->syscalls.table[id].name != NULL)
1027 fprintf(trace->output, "(%s)", trace->syscalls.table[id].name);
1028 fputs(" information\n", trace->output);
1029 }
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001030 return NULL;
1031}
1032
1033static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
1034 struct perf_sample *sample)
1035{
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001036 char *msg;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001037 void *args;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001038 size_t printed = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001039 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001040 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001041 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001042
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001043 if (sc == NULL)
1044 return -1;
1045
1046 if (sc->filtered)
1047 return 0;
1048
Adrian Hunter314add62013-08-27 11:23:03 +03001049 thread = machine__findnew_thread(&trace->host, sample->pid,
1050 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001051 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001052 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001053 return -1;
1054
1055 args = perf_evsel__rawptr(evsel, sample, "args");
1056 if (args == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001057 fprintf(trace->output, "Problems reading syscall arguments\n");
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001058 return -1;
1059 }
1060
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001061 ttrace = thread->priv;
1062
1063 if (ttrace->entry_str == NULL) {
1064 ttrace->entry_str = malloc(1024);
1065 if (!ttrace->entry_str)
1066 return -1;
1067 }
1068
1069 ttrace->entry_time = sample->time;
1070 msg = ttrace->entry_str;
1071 printed += scnprintf(msg + printed, 1024 - printed, "%s(", sc->name);
1072
1073 printed += syscall__scnprintf_args(sc, msg + printed, 1024 - printed, args);
1074
1075 if (!strcmp(sc->name, "exit_group") || !strcmp(sc->name, "exit")) {
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001076 if (!trace->duration_filter) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001077 trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output);
1078 fprintf(trace->output, "%-70s\n", ttrace->entry_str);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001079 }
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001080 } else
1081 ttrace->entry_pending = true;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001082
1083 return 0;
1084}
1085
1086static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
1087 struct perf_sample *sample)
1088{
1089 int ret;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001090 u64 duration = 0;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001091 struct thread *thread;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001092 struct syscall *sc = trace__syscall_info(trace, evsel, sample);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001093 struct thread_trace *ttrace;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001094
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001095 if (sc == NULL)
1096 return -1;
1097
1098 if (sc->filtered)
1099 return 0;
1100
Adrian Hunter314add62013-08-27 11:23:03 +03001101 thread = machine__findnew_thread(&trace->host, sample->pid,
1102 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001103 ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001104 if (ttrace == NULL)
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001105 return -1;
1106
1107 ret = perf_evsel__intval(evsel, sample, "ret");
1108
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001109 ttrace = thread->priv;
1110
1111 ttrace->exit_time = sample->time;
1112
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001113 if (ttrace->entry_time) {
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001114 duration = sample->time - ttrace->entry_time;
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001115 if (trace__filter_duration(trace, duration))
1116 goto out;
1117 } else if (trace->duration_filter)
1118 goto out;
Arnaldo Carvalho de Melo60c907a2012-10-24 17:24:47 -02001119
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001120 trace__fprintf_entry_head(trace, thread, duration, sample->time, trace->output);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001121
1122 if (ttrace->entry_pending) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001123 fprintf(trace->output, "%-70s", ttrace->entry_str);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001124 } else {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001125 fprintf(trace->output, " ... [");
1126 color_fprintf(trace->output, PERF_COLOR_YELLOW, "continued");
1127 fprintf(trace->output, "]: %s()", sc->name);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001128 }
1129
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001130 if (sc->fmt == NULL) {
1131signed_print:
1132 fprintf(trace->output, ") = %d", ret);
1133 } else if (ret < 0 && sc->fmt->errmsg) {
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001134 char bf[256];
1135 const char *emsg = strerror_r(-ret, bf, sizeof(bf)),
1136 *e = audit_errno_to_name(-ret);
1137
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001138 fprintf(trace->output, ") = -1 %s %s", e, emsg);
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001139 } else if (ret == 0 && sc->fmt->timeout)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001140 fprintf(trace->output, ") = 0 Timeout");
Arnaldo Carvalho de Melo04b34722013-08-26 11:36:30 -03001141 else if (sc->fmt->hexret)
1142 fprintf(trace->output, ") = %#x", ret);
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001143 else
Arnaldo Carvalho de Meloda3c9a42013-08-26 11:28:34 -03001144 goto signed_print;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001145
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001146 fputc('\n', trace->output);
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001147out:
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001148 ttrace->entry_pending = false;
1149
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001150 return 0;
1151}
1152
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001153static int trace__sched_stat_runtime(struct trace *trace, struct perf_evsel *evsel,
1154 struct perf_sample *sample)
1155{
1156 u64 runtime = perf_evsel__intval(evsel, sample, "runtime");
1157 double runtime_ms = (double)runtime / NSEC_PER_MSEC;
Adrian Hunter314add62013-08-27 11:23:03 +03001158 struct thread *thread = machine__findnew_thread(&trace->host,
1159 sample->pid,
1160 sample->tid);
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001161 struct thread_trace *ttrace = thread__trace(thread, trace->output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001162
1163 if (ttrace == NULL)
1164 goto out_dump;
1165
1166 ttrace->runtime_ms += runtime_ms;
1167 trace->runtime_ms += runtime_ms;
1168 return 0;
1169
1170out_dump:
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001171 fprintf(trace->output, "%s: comm=%s,pid=%u,runtime=%" PRIu64 ",vruntime=%" PRIu64 ")\n",
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001172 evsel->name,
1173 perf_evsel__strval(evsel, sample, "comm"),
1174 (pid_t)perf_evsel__intval(evsel, sample, "pid"),
1175 runtime,
1176 perf_evsel__intval(evsel, sample, "vruntime"));
1177 return 0;
1178}
1179
David Ahernbdc89662013-08-28 22:29:53 -06001180static bool skip_sample(struct trace *trace, struct perf_sample *sample)
1181{
1182 if ((trace->pid_list && intlist__find(trace->pid_list, sample->pid)) ||
1183 (trace->tid_list && intlist__find(trace->tid_list, sample->tid)))
1184 return false;
1185
1186 if (trace->pid_list || trace->tid_list)
1187 return true;
1188
1189 return false;
1190}
1191
David Ahern6810fc92013-08-28 22:29:52 -06001192static int trace__process_sample(struct perf_tool *tool,
1193 union perf_event *event __maybe_unused,
1194 struct perf_sample *sample,
1195 struct perf_evsel *evsel,
1196 struct machine *machine __maybe_unused)
1197{
1198 struct trace *trace = container_of(tool, struct trace, tool);
1199 int err = 0;
1200
1201 tracepoint_handler handler = evsel->handler.func;
1202
David Ahernbdc89662013-08-28 22:29:53 -06001203 if (skip_sample(trace, sample))
1204 return 0;
1205
David Ahern4bb09192013-09-04 12:37:43 -06001206 if (!trace->full_time && trace->base_time == 0)
David Ahern6810fc92013-08-28 22:29:52 -06001207 trace->base_time = sample->time;
1208
1209 if (handler)
1210 handler(trace, evsel, sample);
1211
1212 return err;
1213}
1214
1215static bool
1216perf_session__has_tp(struct perf_session *session, const char *name)
1217{
1218 struct perf_evsel *evsel;
1219
1220 evsel = perf_evlist__find_tracepoint_by_name(session->evlist, name);
1221
1222 return evsel != NULL;
1223}
1224
David Ahernbdc89662013-08-28 22:29:53 -06001225static int parse_target_str(struct trace *trace)
1226{
1227 if (trace->opts.target.pid) {
1228 trace->pid_list = intlist__new(trace->opts.target.pid);
1229 if (trace->pid_list == NULL) {
1230 pr_err("Error parsing process id string\n");
1231 return -EINVAL;
1232 }
1233 }
1234
1235 if (trace->opts.target.tid) {
1236 trace->tid_list = intlist__new(trace->opts.target.tid);
1237 if (trace->tid_list == NULL) {
1238 pr_err("Error parsing thread id string\n");
1239 return -EINVAL;
1240 }
1241 }
1242
1243 return 0;
1244}
1245
Namhyung Kimf15eb532012-10-05 14:02:16 +09001246static int trace__run(struct trace *trace, int argc, const char **argv)
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001247{
Namhyung Kim334fe7a2013-03-11 16:43:12 +09001248 struct perf_evlist *evlist = perf_evlist__new();
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001249 struct perf_evsel *evsel;
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001250 int err = -1, i;
1251 unsigned long before;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001252 const bool forks = argc > 0;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001253
1254 if (evlist == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001255 fprintf(trace->output, "Not enough memory to run!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001256 goto out;
1257 }
1258
Arnaldo Carvalho de Melo39876e72012-10-03 11:40:22 -03001259 if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) ||
1260 perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001261 fprintf(trace->output, "Couldn't read the raw_syscalls tracepoints information!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001262 goto out_delete_evlist;
1263 }
1264
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001265 if (trace->sched &&
1266 perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime",
1267 trace__sched_stat_runtime)) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001268 fprintf(trace->output, "Couldn't read the sched_stat_runtime tracepoint information!\n");
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001269 goto out_delete_evlist;
1270 }
1271
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001272 err = perf_evlist__create_maps(evlist, &trace->opts.target);
1273 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001274 fprintf(trace->output, "Problems parsing the target to trace, check your options!\n");
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001275 goto out_delete_evlist;
1276 }
1277
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001278 err = trace__symbols_init(trace, evlist);
1279 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001280 fprintf(trace->output, "Problems initializing symbol libraries!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001281 goto out_delete_maps;
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001282 }
1283
Arnaldo Carvalho de Melof77a9512012-12-10 16:41:31 -03001284 perf_evlist__config(evlist, &trace->opts);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001285
Namhyung Kimf15eb532012-10-05 14:02:16 +09001286 signal(SIGCHLD, sig_handler);
1287 signal(SIGINT, sig_handler);
1288
1289 if (forks) {
Namhyung Kim6ef73ec2013-03-11 16:43:15 +09001290 err = perf_evlist__prepare_workload(evlist, &trace->opts.target,
Namhyung Kim55e162e2013-03-11 16:43:17 +09001291 argv, false, false);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001292 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001293 fprintf(trace->output, "Couldn't run the workload!\n");
Namhyung Kim3beb0862013-03-15 14:48:50 +09001294 goto out_delete_maps;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001295 }
1296 }
1297
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001298 err = perf_evlist__open(evlist);
1299 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001300 fprintf(trace->output, "Couldn't create the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001301 goto out_delete_maps;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001302 }
1303
1304 err = perf_evlist__mmap(evlist, UINT_MAX, false);
1305 if (err < 0) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001306 fprintf(trace->output, "Couldn't mmap the events: %s\n", strerror(errno));
Namhyung Kim3beb0862013-03-15 14:48:50 +09001307 goto out_close_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001308 }
1309
1310 perf_evlist__enable(evlist);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001311
1312 if (forks)
1313 perf_evlist__start_workload(evlist);
1314
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001315 trace->multiple_threads = evlist->threads->map[0] == -1 || evlist->threads->nr > 1;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001316again:
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001317 before = trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001318
1319 for (i = 0; i < evlist->nr_mmaps; i++) {
1320 union perf_event *event;
1321
1322 while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
1323 const u32 type = event->header.type;
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001324 tracepoint_handler handler;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001325 struct perf_sample sample;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001326
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001327 ++trace->nr_events;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001328
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001329 err = perf_evlist__parse_sample(evlist, event, &sample);
1330 if (err) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001331 fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001332 continue;
1333 }
1334
David Ahern4bb09192013-09-04 12:37:43 -06001335 if (!trace->full_time && trace->base_time == 0)
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001336 trace->base_time = sample.time;
1337
1338 if (type != PERF_RECORD_SAMPLE) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001339 trace__process_event(trace, &trace->host, event);
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001340 continue;
1341 }
1342
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001343 evsel = perf_evlist__id2evsel(evlist, sample.id);
1344 if (evsel == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001345 fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001346 continue;
1347 }
1348
Arnaldo Carvalho de Melo752fde42012-10-06 18:43:19 -03001349 if (sample.raw_data == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001350 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 -03001351 perf_evsel__name(evsel), sample.tid,
1352 sample.cpu, sample.raw_size);
1353 continue;
1354 }
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001355
Arnaldo Carvalho de Meloba3d7de2012-09-28 17:58:36 -03001356 handler = evsel->handler.func;
1357 handler(trace, evsel, &sample);
Arnaldo Carvalho de Melo20c5f102013-09-03 11:55:07 -03001358
1359 if (done)
1360 goto out_unmap_evlist;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001361 }
1362 }
1363
Arnaldo Carvalho de Meloefd57452012-10-17 17:09:46 -03001364 if (trace->nr_events == before) {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001365 if (done)
Namhyung Kim3beb0862013-03-15 14:48:50 +09001366 goto out_unmap_evlist;
Namhyung Kimf15eb532012-10-05 14:02:16 +09001367
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001368 poll(evlist->pollfd, evlist->nr_fds, -1);
Namhyung Kimf15eb532012-10-05 14:02:16 +09001369 }
1370
1371 if (done)
1372 perf_evlist__disable(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001373
1374 goto again;
1375
Namhyung Kim3beb0862013-03-15 14:48:50 +09001376out_unmap_evlist:
1377 perf_evlist__munmap(evlist);
1378out_close_evlist:
1379 perf_evlist__close(evlist);
1380out_delete_maps:
1381 perf_evlist__delete_maps(evlist);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001382out_delete_evlist:
1383 perf_evlist__delete(evlist);
1384out:
1385 return err;
1386}
1387
David Ahern6810fc92013-08-28 22:29:52 -06001388static int trace__replay(struct trace *trace)
1389{
1390 const struct perf_evsel_str_handler handlers[] = {
1391 { "raw_syscalls:sys_enter", trace__sys_enter, },
1392 { "raw_syscalls:sys_exit", trace__sys_exit, },
1393 };
1394
1395 struct perf_session *session;
1396 int err = -1;
1397
1398 trace->tool.sample = trace__process_sample;
1399 trace->tool.mmap = perf_event__process_mmap;
David Ahern384c6712013-09-22 19:44:58 -06001400 trace->tool.mmap2 = perf_event__process_mmap2;
David Ahern6810fc92013-08-28 22:29:52 -06001401 trace->tool.comm = perf_event__process_comm;
1402 trace->tool.exit = perf_event__process_exit;
1403 trace->tool.fork = perf_event__process_fork;
1404 trace->tool.attr = perf_event__process_attr;
1405 trace->tool.tracing_data = perf_event__process_tracing_data;
1406 trace->tool.build_id = perf_event__process_build_id;
1407
1408 trace->tool.ordered_samples = true;
1409 trace->tool.ordering_requires_timestamps = true;
1410
1411 /* add tid to output */
1412 trace->multiple_threads = true;
1413
1414 if (symbol__init() < 0)
1415 return -1;
1416
1417 session = perf_session__new(input_name, O_RDONLY, 0, false,
1418 &trace->tool);
1419 if (session == NULL)
1420 return -ENOMEM;
1421
1422 err = perf_session__set_tracepoints_handlers(session, handlers);
1423 if (err)
1424 goto out;
1425
1426 if (!perf_session__has_tp(session, "raw_syscalls:sys_enter")) {
1427 pr_err("Data file does not have raw_syscalls:sys_enter events\n");
1428 goto out;
1429 }
1430
1431 if (!perf_session__has_tp(session, "raw_syscalls:sys_exit")) {
1432 pr_err("Data file does not have raw_syscalls:sys_exit events\n");
1433 goto out;
1434 }
1435
David Ahernbdc89662013-08-28 22:29:53 -06001436 err = parse_target_str(trace);
1437 if (err != 0)
1438 goto out;
1439
David Ahern6810fc92013-08-28 22:29:52 -06001440 setup_pager();
1441
1442 err = perf_session__process_events(session, &trace->tool);
1443 if (err)
1444 pr_err("Failed to process events, error %d", err);
1445
1446out:
1447 perf_session__delete(session);
1448
1449 return err;
1450}
1451
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001452static size_t trace__fprintf_threads_header(FILE *fp)
1453{
1454 size_t printed;
1455
1456 printed = fprintf(fp, "\n _____________________________________________________________________\n");
1457 printed += fprintf(fp," __) Summary of events (__\n\n");
1458 printed += fprintf(fp," [ task - pid ] [ events ] [ ratio ] [ runtime ]\n");
1459 printed += fprintf(fp," _____________________________________________________________________\n\n");
1460
1461 return printed;
1462}
1463
1464static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
1465{
1466 size_t printed = trace__fprintf_threads_header(fp);
1467 struct rb_node *nd;
1468
1469 for (nd = rb_first(&trace->host.threads); nd; nd = rb_next(nd)) {
1470 struct thread *thread = rb_entry(nd, struct thread, rb_node);
1471 struct thread_trace *ttrace = thread->priv;
1472 const char *color;
1473 double ratio;
1474
1475 if (ttrace == NULL)
1476 continue;
1477
1478 ratio = (double)ttrace->nr_events / trace->nr_events * 100.0;
1479
1480 color = PERF_COLOR_NORMAL;
1481 if (ratio > 50.0)
1482 color = PERF_COLOR_RED;
1483 else if (ratio > 25.0)
1484 color = PERF_COLOR_GREEN;
1485 else if (ratio > 5.0)
1486 color = PERF_COLOR_YELLOW;
1487
1488 printed += color_fprintf(fp, color, "%20s", thread->comm);
Adrian Hunter38051232013-07-04 16:20:31 +03001489 printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001490 printed += color_fprintf(fp, color, "%5.1f%%", ratio);
1491 printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
1492 }
1493
1494 return printed;
1495}
1496
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001497static int trace__set_duration(const struct option *opt, const char *str,
1498 int unset __maybe_unused)
1499{
1500 struct trace *trace = opt->value;
1501
1502 trace->duration_filter = atof(str);
1503 return 0;
1504}
1505
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001506static int trace__open_output(struct trace *trace, const char *filename)
1507{
1508 struct stat st;
1509
1510 if (!stat(filename, &st) && st.st_size) {
1511 char oldname[PATH_MAX];
1512
1513 scnprintf(oldname, sizeof(oldname), "%s.old", filename);
1514 unlink(oldname);
1515 rename(filename, oldname);
1516 }
1517
1518 trace->output = fopen(filename, "w");
1519
1520 return trace->output == NULL ? -errno : 0;
1521}
1522
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001523int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
1524{
1525 const char * const trace_usage[] = {
Namhyung Kimf15eb532012-10-05 14:02:16 +09001526 "perf trace [<options>] [<command>]",
1527 "perf trace [<options>] -- <command> [<options>]",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001528 NULL
1529 };
1530 struct trace trace = {
1531 .audit_machine = audit_detect_machine(),
1532 .syscalls = {
1533 . max = -1,
1534 },
1535 .opts = {
1536 .target = {
1537 .uid = UINT_MAX,
1538 .uses_mmap = true,
1539 },
1540 .user_freq = UINT_MAX,
1541 .user_interval = ULLONG_MAX,
1542 .no_delay = true,
1543 .mmap_pages = 1024,
1544 },
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001545 .output = stdout,
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001546 .show_comm = true,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001547 };
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001548 const char *output_name = NULL;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001549 const char *ev_qualifier_str = NULL;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001550 const struct option trace_options[] = {
Arnaldo Carvalho de Melo50c95cb2013-09-12 12:35:21 -03001551 OPT_BOOLEAN(0, "comm", &trace.show_comm,
1552 "show the thread COMM next to its id"),
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001553 OPT_STRING('e', "expr", &ev_qualifier_str, "expr",
1554 "list of events to trace"),
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001555 OPT_STRING('o', "output", &output_name, "file", "output file name"),
David Ahern6810fc92013-08-28 22:29:52 -06001556 OPT_STRING('i', "input", &input_name, "file", "Analyze events in file"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001557 OPT_STRING('p', "pid", &trace.opts.target.pid, "pid",
1558 "trace events on existing process id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001559 OPT_STRING('t', "tid", &trace.opts.target.tid, "tid",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001560 "trace events on existing thread id"),
David Ahernac9be8e2013-08-20 11:15:45 -06001561 OPT_BOOLEAN('a', "all-cpus", &trace.opts.target.system_wide,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001562 "system-wide collection from all CPUs"),
David Ahernac9be8e2013-08-20 11:15:45 -06001563 OPT_STRING('C', "cpu", &trace.opts.target.cpu_list, "cpu",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001564 "list of cpus to monitor"),
David Ahern6810fc92013-08-28 22:29:52 -06001565 OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit,
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001566 "child tasks do not inherit counters"),
Jiri Olsa994a1f72013-09-01 12:36:12 +02001567 OPT_CALLBACK('m', "mmap-pages", &trace.opts.mmap_pages, "pages",
1568 "number of mmap data pages",
1569 perf_evlist__parse_mmap_pages),
David Ahernac9be8e2013-08-20 11:15:45 -06001570 OPT_STRING('u', "uid", &trace.opts.target.uid_str, "user",
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001571 "user to profile"),
Arnaldo Carvalho de Meloae9ed032012-10-08 09:56:00 -03001572 OPT_CALLBACK(0, "duration", &trace, "float",
1573 "show only events with duration > N.M ms",
1574 trace__set_duration),
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001575 OPT_BOOLEAN(0, "sched", &trace.sched, "show blocking scheduler events"),
Arnaldo Carvalho de Melo7c304ee02013-08-22 16:49:54 -03001576 OPT_INCR('v', "verbose", &verbose, "be more verbose"),
David Ahern4bb09192013-09-04 12:37:43 -06001577 OPT_BOOLEAN('T', "time", &trace.full_time,
1578 "Show full timestamp, not time relative to first start"),
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001579 OPT_END()
1580 };
1581 int err;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001582 char bf[BUFSIZ];
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001583
1584 argc = parse_options(argc, argv, trace_options, trace_usage, 0);
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001585
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001586 if (output_name != NULL) {
1587 err = trace__open_output(&trace, output_name);
1588 if (err < 0) {
1589 perror("failed to create output file");
1590 goto out;
1591 }
1592 }
1593
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001594 if (ev_qualifier_str != NULL) {
Arnaldo Carvalho de Melob059efd2013-08-21 12:56:21 -03001595 const char *s = ev_qualifier_str;
1596
1597 trace.not_ev_qualifier = *s == '!';
1598 if (trace.not_ev_qualifier)
1599 ++s;
1600 trace.ev_qualifier = strlist__new(true, s);
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001601 if (trace.ev_qualifier == NULL) {
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001602 fputs("Not enough memory to parse event qualifier",
1603 trace.output);
1604 err = -ENOMEM;
1605 goto out_close;
Arnaldo Carvalho de Melo2ae3a312013-08-09 12:28:31 -03001606 }
1607 }
1608
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001609 err = perf_target__validate(&trace.opts.target);
1610 if (err) {
1611 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001612 fprintf(trace.output, "%s", bf);
1613 goto out_close;
Namhyung Kim32caf0d2012-10-05 14:02:13 +09001614 }
1615
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001616 err = perf_target__parse_uid(&trace.opts.target);
1617 if (err) {
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001618 perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf));
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001619 fprintf(trace.output, "%s", bf);
1620 goto out_close;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001621 }
1622
Namhyung Kimf15eb532012-10-05 14:02:16 +09001623 if (!argc && perf_target__none(&trace.opts.target))
Namhyung Kimee761202012-10-05 14:02:14 +09001624 trace.opts.target.system_wide = true;
1625
David Ahern6810fc92013-08-28 22:29:52 -06001626 if (input_name)
1627 err = trace__replay(&trace);
1628 else
1629 err = trace__run(&trace, argc, argv);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001630
1631 if (trace.sched && !err)
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001632 trace__fprintf_thread_summary(&trace, trace.output);
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001633
Arnaldo Carvalho de Meloc24ff992013-08-19 12:01:10 -03001634out_close:
1635 if (output_name != NULL)
1636 fclose(trace.output);
1637out:
Arnaldo Carvalho de Melo1302d882012-10-17 17:13:12 -03001638 return err;
Arnaldo Carvalho de Melo514f1c62012-09-26 20:05:56 -03001639}